diff options
Diffstat (limited to 'bgpd/bgp_packet.c')
| -rw-r--r-- | bgpd/bgp_packet.c | 4124 | 
1 files changed, 2059 insertions, 2065 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index b1fa50974b..f6a1c417b2 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -27,7 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "command.h"  #include "log.h"  #include "memory.h" -#include "sockunion.h"		/* for inet_ntop () */ +#include "sockunion.h" /* for inet_ntop () */  #include "sockopt.h"  #include "linklist.h"  #include "plist.h" @@ -55,2286 +55,2280 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_updgrp.h"  /* Set up BGP packet marker and packet type. */ -int -bgp_packet_set_marker (struct stream *s, u_char type) +int bgp_packet_set_marker(struct stream *s, u_char type)  { -  int i; +	int i; -  /* Fill in marker. */ -  for (i = 0; i < BGP_MARKER_SIZE; i++) -    stream_putc (s, 0xff); +	/* Fill in marker. */ +	for (i = 0; i < BGP_MARKER_SIZE; i++) +		stream_putc(s, 0xff); -  /* Dummy total length. This field is should be filled in later on. */ -  stream_putw (s, 0); +	/* Dummy total length. This field is should be filled in later on. */ +	stream_putw(s, 0); -  /* BGP packet type. */ -  stream_putc (s, type); +	/* BGP packet type. */ +	stream_putc(s, type); -  /* Return current stream size. */ -  return stream_get_endp (s); +	/* Return current stream size. */ +	return stream_get_endp(s);  }  /* Set BGP packet header size entry.  If size is zero then use current     stream size. */ -int -bgp_packet_set_size (struct stream *s) +int bgp_packet_set_size(struct stream *s)  { -  int cp; +	int cp; -  /* Preserve current pointer. */ -  cp = stream_get_endp (s); -  stream_putw_at (s, BGP_MARKER_SIZE, cp); +	/* Preserve current pointer. */ +	cp = stream_get_endp(s); +	stream_putw_at(s, BGP_MARKER_SIZE, cp); -  return cp; +	return cp;  }  /* Add new packet to the peer. */ -void -bgp_packet_add (struct peer *peer, struct stream *s) +void bgp_packet_add(struct peer *peer, struct stream *s)  { -  /* Add packet to the end of list. */ -  stream_fifo_push (peer->obuf, s); +	/* Add packet to the end of list. */ +	stream_fifo_push(peer->obuf, s);  }  /* Free first packet. */ -static void -bgp_packet_delete (struct peer *peer) +static void bgp_packet_delete(struct peer *peer)  { -  stream_free (stream_fifo_pop (peer->obuf)); +	stream_free(stream_fifo_pop(peer->obuf));  }  /* Check file descriptor whether connect is established. */ -int -bgp_connect_check (struct peer *peer, int change_state) +int bgp_connect_check(struct peer *peer, int change_state)  { -  int status; -  socklen_t slen; -  int ret; - -  /* Anyway I have to reset read and write thread. */ -  BGP_READ_OFF (peer->t_read); -  BGP_WRITE_OFF (peer->t_write); - -  /* Check file descriptor. */ -  slen = sizeof (status); -  ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); - -  /* If getsockopt is fail, this is fatal error. */ -  if (ret < 0) -    { -      zlog_info ("can't get sockopt for nonblocking connect"); -      BGP_EVENT_ADD (peer, TCP_fatal_error); -      return -1; -    }       - -  /* When status is 0 then TCP connection is established. */ -  if (status == 0) -    { -      BGP_EVENT_ADD (peer, TCP_connection_open); -      return 1; -    } -  else -    { -      if (bgp_debug_neighbor_events(peer)) -	  zlog_debug ("%s [Event] Connect failed (%s)", -		      peer->host, safe_strerror (errno)); -      if (change_state) -	BGP_EVENT_ADD (peer, TCP_connection_open_failed); -      return 0; -    } +	int status; +	socklen_t slen; +	int ret; + +	/* Anyway I have to reset read and write thread. */ +	BGP_READ_OFF(peer->t_read); +	BGP_WRITE_OFF(peer->t_write); + +	/* Check file descriptor. */ +	slen = sizeof(status); +	ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *)&status, +			 &slen); + +	/* If getsockopt is fail, this is fatal error. */ +	if (ret < 0) { +		zlog_info("can't get sockopt for nonblocking connect"); +		BGP_EVENT_ADD(peer, TCP_fatal_error); +		return -1; +	} + +	/* When status is 0 then TCP connection is established. */ +	if (status == 0) { +		BGP_EVENT_ADD(peer, TCP_connection_open); +		return 1; +	} else { +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s [Event] Connect failed (%s)", peer->host, +				   safe_strerror(errno)); +		if (change_state) +			BGP_EVENT_ADD(peer, TCP_connection_open_failed); +		return 0; +	}  } -static struct stream * -bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) +static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi, +					    safi_t safi)  { -  struct stream *s; -  iana_afi_t pkt_afi; -  safi_t pkt_safi; - -  if (DISABLE_BGP_ANNOUNCE) -    return NULL; - -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host); - -  s = stream_new (BGP_MAX_PACKET_SIZE); - -  /* Make BGP update packet. */ -  bgp_packet_set_marker (s, BGP_MSG_UPDATE); - -  /* Unfeasible Routes Length */ -  stream_putw (s, 0); - -  if (afi == AFI_IP && safi == SAFI_UNICAST) -    { -      /* Total Path Attribute Length */ -      stream_putw (s, 0); -    } -  else -    { -      /* Convert AFI, SAFI to values for packet. */ -      bgp_map_afi_safi_int2iana (afi, safi, &pkt_afi, &pkt_safi); - -      /* Total Path Attribute Length */ -      stream_putw (s, 6); -      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); -      stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); -      stream_putc (s, 3); -      stream_putw (s, pkt_afi); -      stream_putc (s, pkt_safi); -    } - -  bgp_packet_set_size (s); -  bgp_packet_add (peer, s); -  return s; +	struct stream *s; +	iana_afi_t pkt_afi; +	safi_t pkt_safi; + +	if (DISABLE_BGP_ANNOUNCE) +		return NULL; + +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug("send End-of-RIB for %s to %s", +			   afi_safi_print(afi, safi), peer->host); + +	s = stream_new(BGP_MAX_PACKET_SIZE); + +	/* Make BGP update packet. */ +	bgp_packet_set_marker(s, BGP_MSG_UPDATE); + +	/* Unfeasible Routes Length */ +	stream_putw(s, 0); + +	if (afi == AFI_IP && safi == SAFI_UNICAST) { +		/* Total Path Attribute Length */ +		stream_putw(s, 0); +	} else { +		/* Convert AFI, SAFI to values for packet. */ +		bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + +		/* Total Path Attribute Length */ +		stream_putw(s, 6); +		stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); +		stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI); +		stream_putc(s, 3); +		stream_putw(s, pkt_afi); +		stream_putc(s, pkt_safi); +	} + +	bgp_packet_set_size(s); +	bgp_packet_add(peer, s); +	return s;  }  /* Get next packet to be written.  */ -static struct stream * -bgp_write_packet (struct peer *peer) +static struct stream *bgp_write_packet(struct peer *peer)  { -  struct stream *s = NULL; -  struct peer_af *paf; -  struct bpacket *next_pkt; -  afi_t afi; -  safi_t safi; - -  s = stream_fifo_head (peer->obuf); -  if (s) -    return s; - -  /* -   * The code beyond this part deals with update packets, proceed only -   * if peer is Established and updates are not on hold (as part of -   * update-delay post processing). -   */ -  if (peer->status != Established) -    return NULL; - -  if (peer->bgp && peer->bgp->main_peers_update_hold) -    return NULL; - -  for (afi = AFI_IP; afi < AFI_MAX; afi++) -    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) -      { -        paf = peer_af_find (peer, afi, safi); -        if (!paf || !PAF_SUBGRP(paf)) -          continue; -        next_pkt = paf->next_pkt_to_send; - -	/* Try to generate a packet for the peer if we are at the end of -	 * the list. Always try to push out WITHDRAWs first. */ -        if (!next_pkt || !next_pkt->buffer) -	  { -	    next_pkt = subgroup_withdraw_packet(PAF_SUBGRP(paf)); -            if (!next_pkt || !next_pkt->buffer) -	      subgroup_update_packet (PAF_SUBGRP(paf)); -	    next_pkt = paf->next_pkt_to_send; -	  } - -	/* If we still don't have a packet to send to the peer, then -	 * try to find out out if we have to send eor or if not, skip to -	 * the next AFI, SAFI. -	 * Don't send the EOR prematurely... if the subgroup's coalesce -	 * timer is running, the adjacency-out structure is not created -	 * yet. +	struct stream *s = NULL; +	struct peer_af *paf; +	struct bpacket *next_pkt; +	afi_t afi; +	safi_t safi; + +	s = stream_fifo_head(peer->obuf); +	if (s) +		return s; + +	/* +	 * The code beyond this part deals with update packets, proceed only +	 * if peer is Established and updates are not on hold (as part of +	 * update-delay post processing).  	 */ -        if (!next_pkt || !next_pkt->buffer) -          { -	    if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) -	      { -		if (!(PAF_SUBGRP(paf))->t_coalesce && -		    peer->afc_nego[afi][safi] && peer->synctime -		    && ! CHECK_FLAG (peer->af_sflags[afi][safi], -				     PEER_STATUS_EOR_SEND) -                    && safi != SAFI_EVPN) -		  { -		    SET_FLAG (peer->af_sflags[afi][safi], -			      PEER_STATUS_EOR_SEND); -		    return bgp_update_packet_eor (peer, afi, safi); -		  } -	      } -	    continue; -	  } - - -        /* -	 * Found a packet template to send, overwrite packet with appropriate -         * attributes from peer and advance peer -	 */ -        s = bpacket_reformat_for_peer (next_pkt, paf); -        bpacket_queue_advance_peer (paf); -        return s; -      } +	if (peer->status != Established) +		return NULL; + +	if (peer->bgp && peer->bgp->main_peers_update_hold) +		return NULL; + +	for (afi = AFI_IP; afi < AFI_MAX; afi++) +		for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { +			paf = peer_af_find(peer, afi, safi); +			if (!paf || !PAF_SUBGRP(paf)) +				continue; +			next_pkt = paf->next_pkt_to_send; + +			/* Try to generate a packet for the peer if we are at +			 * the end of +			 * the list. Always try to push out WITHDRAWs first. */ +			if (!next_pkt || !next_pkt->buffer) { +				next_pkt = subgroup_withdraw_packet( +					PAF_SUBGRP(paf)); +				if (!next_pkt || !next_pkt->buffer) +					subgroup_update_packet(PAF_SUBGRP(paf)); +				next_pkt = paf->next_pkt_to_send; +			} + +			/* If we still don't have a packet to send to the peer, +			 * then +			 * try to find out out if we have to send eor or if not, +			 * skip to +			 * the next AFI, SAFI. +			 * Don't send the EOR prematurely... if the subgroup's +			 * coalesce +			 * timer is running, the adjacency-out structure is not +			 * created +			 * yet. +			 */ +			if (!next_pkt || !next_pkt->buffer) { +				if (CHECK_FLAG(peer->cap, +					       PEER_CAP_RESTART_RCV)) { +					if (!(PAF_SUBGRP(paf))->t_coalesce +					    && peer->afc_nego[afi][safi] +					    && peer->synctime +					    && !CHECK_FLAG( +						       peer->af_sflags[afi] +								      [safi], +						       PEER_STATUS_EOR_SEND) +					    && safi != SAFI_EVPN) { +						SET_FLAG(peer->af_sflags[afi] +									[safi], +							 PEER_STATUS_EOR_SEND); +						return bgp_update_packet_eor( +							peer, afi, safi); +					} +				} +				continue; +			} + + +			/* +			 * Found a packet template to send, overwrite packet +			 * with appropriate +			 * attributes from peer and advance peer +			 */ +			s = bpacket_reformat_for_peer(next_pkt, paf); +			bpacket_queue_advance_peer(paf); +			return s; +		} -  return NULL; +	return NULL;  }  /* The next action for the peer from a write perspective */ -static void -bgp_write_proceed_actions (struct peer *peer) +static void bgp_write_proceed_actions(struct peer *peer)  { -  afi_t afi; -  safi_t safi; -  struct peer_af *paf; -  struct bpacket *next_pkt; -  int fullq_found = 0; -  struct update_subgroup *subgrp; - -  if (stream_fifo_head (peer->obuf)) -    { -      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); -      return; -    } - -   for (afi = AFI_IP; afi < AFI_MAX; afi++) -     for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) -      { -        paf = peer_af_find (peer, afi, safi); -        if (!paf) -          continue; -        subgrp = paf->subgroup; -        if (!subgrp) -          continue; - -        next_pkt = paf->next_pkt_to_send; -        if (next_pkt && next_pkt->buffer) -          { -            BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); -            return; -          } - -        /* No packets readily available for AFI/SAFI, are there subgroup packets -         * that need to be generated? */ -        if (bpacket_queue_is_full(SUBGRP_INST(subgrp), -                                  SUBGRP_PKTQ(subgrp))) -          fullq_found = 1; -        else if (subgroup_packets_to_build (subgrp)) -          { -            BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); -            return; -          } - -        /* No packets to send, see if EOR is pending */ -        if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) -          { -            if (!subgrp->t_coalesce && -                peer->afc_nego[afi][safi] && -                peer->synctime && -                !CHECK_FLAG(peer->af_sflags[afi][safi], -                            PEER_STATUS_EOR_SEND) && -                safi != SAFI_MPLS_VPN) -              { -                BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); -                return; -              } - -          } -      } -  if (fullq_found) -    { -      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); -      return; -    } +	afi_t afi; +	safi_t safi; +	struct peer_af *paf; +	struct bpacket *next_pkt; +	int fullq_found = 0; +	struct update_subgroup *subgrp; + +	if (stream_fifo_head(peer->obuf)) { +		BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd); +		return; +	} + +	for (afi = AFI_IP; afi < AFI_MAX; afi++) +		for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { +			paf = peer_af_find(peer, afi, safi); +			if (!paf) +				continue; +			subgrp = paf->subgroup; +			if (!subgrp) +				continue; + +			next_pkt = paf->next_pkt_to_send; +			if (next_pkt && next_pkt->buffer) { +				BGP_WRITE_ON(peer->t_write, bgp_write, +					     peer->fd); +				return; +			} + +			/* No packets readily available for AFI/SAFI, are there +			 * subgroup packets +			 * that need to be generated? */ +			if (bpacket_queue_is_full(SUBGRP_INST(subgrp), +						  SUBGRP_PKTQ(subgrp))) +				fullq_found = 1; +			else if (subgroup_packets_to_build(subgrp)) { +				BGP_WRITE_ON(peer->t_write, bgp_write, +					     peer->fd); +				return; +			} + +			/* No packets to send, see if EOR is pending */ +			if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) { +				if (!subgrp->t_coalesce +				    && peer->afc_nego[afi][safi] +				    && peer->synctime +				    && !CHECK_FLAG(peer->af_sflags[afi][safi], +						   PEER_STATUS_EOR_SEND) +				    && safi != SAFI_MPLS_VPN) { +					BGP_WRITE_ON(peer->t_write, bgp_write, +						     peer->fd); +					return; +				} +			} +		} +	if (fullq_found) { +		BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd); +		return; +	}  }  /* Write packet to the peer. */ -int -bgp_write (struct thread *thread) +int bgp_write(struct thread *thread)  { -  struct peer *peer; -  u_char type; -  struct stream *s; -  int num; -  int update_last_write = 0; -  unsigned int count = 0; -  unsigned int oc = 0; - -  /* Yes first of all get peer pointer. */ -  peer = THREAD_ARG (thread); -  peer->t_write = NULL; - -  /* For non-blocking IO check. */ -  if (peer->status == Connect) -    { -      bgp_connect_check (peer, 1); -      return 0; -    } - -  s = bgp_write_packet (peer); -  if (!s) -    { -      bgp_write_proceed_actions (peer); -      return 0; -    } - -  sockopt_cork (peer->fd, 1); - -  oc = peer->update_out; - -  /* Nonblocking write until TCP output buffer is full.  */ -  do -    { -      int writenum; - -      /* Number of bytes to be sent.  */ -      writenum = stream_get_endp (s) - stream_get_getp (s); - -      /* Call write() system call.  */ -      num = write (peer->fd, STREAM_PNT (s), writenum); -      if (num < 0) -	{ -	  /* write failed either retry needed or error */ -	  if (ERRNO_IO_RETRY(errno)) -		break; - -          BGP_EVENT_ADD (peer, TCP_fatal_error); -	  return 0; +	struct peer *peer; +	u_char type; +	struct stream *s; +	int num; +	int update_last_write = 0; +	unsigned int count = 0; +	unsigned int oc = 0; + +	/* Yes first of all get peer pointer. */ +	peer = THREAD_ARG(thread); +	peer->t_write = NULL; + +	/* For non-blocking IO check. */ +	if (peer->status == Connect) { +		bgp_connect_check(peer, 1); +		return 0;  	} -      if (num != writenum) -	{ -	  /* Partial write */ -	  stream_forward_getp (s, num); -	  break; +	s = bgp_write_packet(peer); +	if (!s) { +		bgp_write_proceed_actions(peer); +		return 0;  	} -      /* Retrieve BGP packet type. */ -      stream_set_getp (s, BGP_MARKER_SIZE + 2); -      type = stream_getc (s); +	sockopt_cork(peer->fd, 1); -      switch (type) -	{ -	case BGP_MSG_OPEN: -	  peer->open_out++; -	  break; -	case BGP_MSG_UPDATE: -	  peer->update_out++; -	  break; -	case BGP_MSG_NOTIFY: -	  peer->notify_out++; -	  /* Double start timer. */ -	  peer->v_start *= 2; +	oc = peer->update_out; -	  /* Overflow check. */ -	  if (peer->v_start >= (60 * 2)) -	    peer->v_start = (60 * 2); +	/* Nonblocking write until TCP output buffer is full.  */ +	do { +		int writenum; -	  /* Flush any existing events */ -	  BGP_EVENT_ADD (peer, BGP_Stop); -	  goto done; - -	case BGP_MSG_KEEPALIVE: -	  peer->keepalive_out++; -	  break; -	case BGP_MSG_ROUTE_REFRESH_NEW: -	case BGP_MSG_ROUTE_REFRESH_OLD: -	  peer->refresh_out++; -	  break; -	case BGP_MSG_CAPABILITY: -	  peer->dynamic_cap_out++; -	  break; -	} +		/* Number of bytes to be sent.  */ +		writenum = stream_get_endp(s) - stream_get_getp(s); -      /* OK we send packet so delete it. */ -      bgp_packet_delete (peer); -      update_last_write = 1; -    } -  while (++count < peer->bgp->wpkt_quanta && -	 (s = bgp_write_packet (peer)) != NULL); +		/* Call write() system call.  */ +		num = write(peer->fd, STREAM_PNT(s), writenum); +		if (num < 0) { +			/* write failed either retry needed or error */ +			if (ERRNO_IO_RETRY(errno)) +				break; -  bgp_write_proceed_actions (peer); +			BGP_EVENT_ADD(peer, TCP_fatal_error); +			return 0; +		} - done: -  /* Update last_update if UPDATEs were written. */ -  if (peer->update_out > oc) -    peer->last_update = bgp_clock (); +		if (num != writenum) { +			/* Partial write */ +			stream_forward_getp(s, num); +			break; +		} -  /* If we TXed any flavor of packet update last_write */ -  if (update_last_write) -    peer->last_write = bgp_clock (); +		/* Retrieve BGP packet type. */ +		stream_set_getp(s, BGP_MARKER_SIZE + 2); +		type = stream_getc(s); + +		switch (type) { +		case BGP_MSG_OPEN: +			peer->open_out++; +			break; +		case BGP_MSG_UPDATE: +			peer->update_out++; +			break; +		case BGP_MSG_NOTIFY: +			peer->notify_out++; +			/* Double start timer. */ +			peer->v_start *= 2; + +			/* Overflow check. */ +			if (peer->v_start >= (60 * 2)) +				peer->v_start = (60 * 2); + +			/* Flush any existing events */ +			BGP_EVENT_ADD(peer, BGP_Stop); +			goto done; + +		case BGP_MSG_KEEPALIVE: +			peer->keepalive_out++; +			break; +		case BGP_MSG_ROUTE_REFRESH_NEW: +		case BGP_MSG_ROUTE_REFRESH_OLD: +			peer->refresh_out++; +			break; +		case BGP_MSG_CAPABILITY: +			peer->dynamic_cap_out++; +			break; +		} -  sockopt_cork (peer->fd, 0); -  return 0; -} +		/* OK we send packet so delete it. */ +		bgp_packet_delete(peer); +		update_last_write = 1; +	} while (++count < peer->bgp->wpkt_quanta +		 && (s = bgp_write_packet(peer)) != NULL); -/* This is only for sending NOTIFICATION message to neighbor. */ -static int -bgp_write_notify (struct peer *peer) -{ -  int ret, val; -  u_char type; -  struct stream *s; +	bgp_write_proceed_actions(peer); -  /* There should be at least one packet. */ -  s = stream_fifo_head (peer->obuf); -  if (!s) -    return 0; -  assert (stream_get_endp (s) >= BGP_HEADER_SIZE); +done: +	/* Update last_update if UPDATEs were written. */ +	if (peer->update_out > oc) +		peer->last_update = bgp_clock(); -  /* Stop collecting data within the socket */ -  sockopt_cork (peer->fd, 0); +	/* If we TXed any flavor of packet update last_write */ +	if (update_last_write) +		peer->last_write = bgp_clock(); -  /* socket is in nonblocking mode, if we can't deliver the NOTIFY, well, -   * we only care about getting a clean shutdown at this point. */ -  ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); +	sockopt_cork(peer->fd, 0); +	return 0; +} -  /* only connection reset/close gets counted as TCP_fatal_error, failure -   * to write the entire NOTIFY doesn't get different FSM treatment */ -  if (ret <= 0) -    { -      BGP_EVENT_ADD (peer, TCP_fatal_error); -      return 0; -    } +/* This is only for sending NOTIFICATION message to neighbor. */ +static int bgp_write_notify(struct peer *peer) +{ +	int ret, val; +	u_char type; +	struct stream *s; + +	/* There should be at least one packet. */ +	s = stream_fifo_head(peer->obuf); +	if (!s) +		return 0; +	assert(stream_get_endp(s) >= BGP_HEADER_SIZE); + +	/* Stop collecting data within the socket */ +	sockopt_cork(peer->fd, 0); + +	/* socket is in nonblocking mode, if we can't deliver the NOTIFY, well, +	 * we only care about getting a clean shutdown at this point. */ +	ret = write(peer->fd, STREAM_DATA(s), stream_get_endp(s)); + +	/* only connection reset/close gets counted as TCP_fatal_error, failure +	 * to write the entire NOTIFY doesn't get different FSM treatment */ +	if (ret <= 0) { +		BGP_EVENT_ADD(peer, TCP_fatal_error); +		return 0; +	} -  /* Disable Nagle, make NOTIFY packet go out right away */ -  val = 1; -  (void) setsockopt (peer->fd, IPPROTO_TCP, TCP_NODELAY, -                            (char *) &val, sizeof (val)); +	/* Disable Nagle, make NOTIFY packet go out right away */ +	val = 1; +	(void)setsockopt(peer->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, +			 sizeof(val)); -  /* Retrieve BGP packet type. */ -  stream_set_getp (s, BGP_MARKER_SIZE + 2); -  type = stream_getc (s); +	/* Retrieve BGP packet type. */ +	stream_set_getp(s, BGP_MARKER_SIZE + 2); +	type = stream_getc(s); -  assert (type == BGP_MSG_NOTIFY); +	assert(type == BGP_MSG_NOTIFY); -  /* Type should be notify. */ -  peer->notify_out++; +	/* Type should be notify. */ +	peer->notify_out++; -  /* Double start timer. */ -  peer->v_start *= 2; +	/* Double start timer. */ +	peer->v_start *= 2; -  /* Overflow check. */ -  if (peer->v_start >= (60 * 2)) -    peer->v_start = (60 * 2); +	/* Overflow check. */ +	if (peer->v_start >= (60 * 2)) +		peer->v_start = (60 * 2); -  /* Handle Graceful Restart case where the state changes to -     Connect instead of Idle */ -  BGP_EVENT_ADD (peer, BGP_Stop); +	/* Handle Graceful Restart case where the state changes to +	   Connect instead of Idle */ +	BGP_EVENT_ADD(peer, BGP_Stop); -  return 0; +	return 0;  }  /* Make keepalive packet and send it to the peer. */ -void -bgp_keepalive_send (struct peer *peer) +void bgp_keepalive_send(struct peer *peer)  { -  struct stream *s; +	struct stream *s; + +	s = stream_new(BGP_MAX_PACKET_SIZE); -  s = stream_new (BGP_MAX_PACKET_SIZE); +	/* Make keepalive packet. */ +	bgp_packet_set_marker(s, BGP_MSG_KEEPALIVE); -  /* Make keepalive packet. */ -  bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE); +	/* Set packet size. */ +	(void)bgp_packet_set_size(s); -  /* Set packet size. */ -  (void)bgp_packet_set_size (s); +	/* Dump packet if debug option is set. */ +	/* bgp_packet_dump (s); */ -  /* Dump packet if debug option is set. */ -  /* bgp_packet_dump (s); */ -  -  if (bgp_debug_keepalive(peer)) -    zlog_debug ("%s sending KEEPALIVE", peer->host);  +	if (bgp_debug_keepalive(peer)) +		zlog_debug("%s sending KEEPALIVE", peer->host); -  /* Add packet to the peer. */ -  bgp_packet_add (peer, s); +	/* Add packet to the peer. */ +	bgp_packet_add(peer, s); -  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +	BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd);  }  /* Make open packet and send it to the peer. */ -void -bgp_open_send (struct peer *peer) +void bgp_open_send(struct peer *peer)  { -  struct stream *s; -  u_int16_t send_holdtime; -  as_t local_as; +	struct stream *s; +	u_int16_t send_holdtime; +	as_t local_as; -  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) -    send_holdtime = peer->holdtime; -  else -    send_holdtime = peer->bgp->default_holdtime; +	if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)) +		send_holdtime = peer->holdtime; +	else +		send_holdtime = peer->bgp->default_holdtime; -  /* local-as Change */ -  if (peer->change_local_as) -    local_as = peer->change_local_as;  -  else -    local_as = peer->local_as;  +	/* local-as Change */ +	if (peer->change_local_as) +		local_as = peer->change_local_as; +	else +		local_as = peer->local_as; -  s = stream_new (BGP_MAX_PACKET_SIZE); +	s = stream_new(BGP_MAX_PACKET_SIZE); -  /* Make open packet. */ -  bgp_packet_set_marker (s, BGP_MSG_OPEN); +	/* Make open packet. */ +	bgp_packet_set_marker(s, BGP_MSG_OPEN); -  /* Set open packet values. */ -  stream_putc (s, BGP_VERSION_4);        /* BGP version */ -  stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as  -                                           : BGP_AS_TRANS); -  stream_putw (s, send_holdtime);     	 /* Hold Time */ -  stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ +	/* Set open packet values. */ +	stream_putc(s, BGP_VERSION_4); /* BGP version */ +	stream_putw(s, +		    (local_as <= BGP_AS_MAX) ? (u_int16_t)local_as +					     : BGP_AS_TRANS); +	stream_putw(s, send_holdtime);		/* Hold Time */ +	stream_put_in_addr(s, &peer->local_id); /* BGP Identifier */ -  /* Set capability code. */ -  bgp_open_capability (s, peer); +	/* Set capability code. */ +	bgp_open_capability(s, peer); -  /* Set BGP packet length. */ -  (void)bgp_packet_set_size (s); +	/* Set BGP packet length. */ +	(void)bgp_packet_set_size(s); -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",  -	       peer->host, BGP_VERSION_4, local_as, -	       send_holdtime, inet_ntoa (peer->local_id)); +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug( +			"%s sending OPEN, version %d, my as %u, holdtime %d, id %s", +			peer->host, BGP_VERSION_4, local_as, send_holdtime, +			inet_ntoa(peer->local_id)); -  /* Dump packet if debug option is set. */ -  /* bgp_packet_dump (s); */ +	/* Dump packet if debug option is set. */ +	/* bgp_packet_dump (s); */ -  /* Add packet to the peer. */ -  bgp_packet_add (peer, s); +	/* Add packet to the peer. */ +	bgp_packet_add(peer, s); -  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +	BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd);  }  /* Send BGP notify packet with data potion. */ -void -bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, -			   u_char *data, size_t datalen) +void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code, +			       u_char *data, size_t datalen)  { -  struct stream *s; -  int length; - -  /* Allocate new stream. */ -  s = stream_new (BGP_MAX_PACKET_SIZE); - -  /* Make nitify packet. */ -  bgp_packet_set_marker (s, BGP_MSG_NOTIFY); - -  /* Set notify packet values. */ -  stream_putc (s, code);        /* BGP notify code */ -  stream_putc (s, sub_code);	/* BGP notify sub_code */ - -  /* If notify data is present. */ -  if (data) -    stream_write (s, data, datalen); -   -  /* Set BGP packet length. */ -  length = bgp_packet_set_size (s); -   -  /* Add packet to the peer. */ -  stream_fifo_clean (peer->obuf); -  bgp_packet_add (peer, s); - -  /* For debug */ -  { -    struct bgp_notify bgp_notify; -    int first = 0; -    int i; -    char c[4]; - -    bgp_notify.code = code; -    bgp_notify.subcode = sub_code; -    bgp_notify.data = NULL; -    bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; -    bgp_notify.raw_data = data; - -    peer->notify.code = bgp_notify.code; -    peer->notify.subcode = bgp_notify.subcode; -     -    if (bgp_notify.length) -      { -	bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); -	for (i = 0; i < bgp_notify.length; i++) -	  if (first) -	    { -	      sprintf (c, " %02x", data[i]); -	      strcat (bgp_notify.data, c); -	    } -	  else -	    { -	      first = 1; -	      sprintf (c, "%02x", data[i]); -	      strcpy (bgp_notify.data, c); -	    } -      } -    bgp_notify_print (peer, &bgp_notify, "sending"); - -    if (bgp_notify.data) -      { -        XFREE (MTYPE_TMP, bgp_notify.data); -        bgp_notify.data = NULL; -        bgp_notify.length = 0; -      } -  } - -  /* peer reset cause */ -  if (code == BGP_NOTIFY_CEASE) -    { -      if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) -        peer->last_reset = PEER_DOWN_USER_RESET; -      else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) -        peer->last_reset = PEER_DOWN_USER_SHUTDOWN; -      else -        peer->last_reset = PEER_DOWN_NOTIFY_SEND; -    } -  else -    peer->last_reset = PEER_DOWN_NOTIFY_SEND; - -  /* Call immediately. */ -  BGP_WRITE_OFF (peer->t_write); - -  bgp_write_notify (peer); +	struct stream *s; +	int length; + +	/* Allocate new stream. */ +	s = stream_new(BGP_MAX_PACKET_SIZE); + +	/* Make nitify packet. */ +	bgp_packet_set_marker(s, BGP_MSG_NOTIFY); + +	/* Set notify packet values. */ +	stream_putc(s, code);     /* BGP notify code */ +	stream_putc(s, sub_code); /* BGP notify sub_code */ + +	/* If notify data is present. */ +	if (data) +		stream_write(s, data, datalen); + +	/* Set BGP packet length. */ +	length = bgp_packet_set_size(s); + +	/* Add packet to the peer. */ +	stream_fifo_clean(peer->obuf); +	bgp_packet_add(peer, s); + +	/* For debug */ +	{ +		struct bgp_notify bgp_notify; +		int first = 0; +		int i; +		char c[4]; + +		bgp_notify.code = code; +		bgp_notify.subcode = sub_code; +		bgp_notify.data = NULL; +		bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; +		bgp_notify.raw_data = data; + +		peer->notify.code = bgp_notify.code; +		peer->notify.subcode = bgp_notify.subcode; + +		if (bgp_notify.length) { +			bgp_notify.data = +				XMALLOC(MTYPE_TMP, bgp_notify.length * 3); +			for (i = 0; i < bgp_notify.length; i++) +				if (first) { +					sprintf(c, " %02x", data[i]); +					strcat(bgp_notify.data, c); +				} else { +					first = 1; +					sprintf(c, "%02x", data[i]); +					strcpy(bgp_notify.data, c); +				} +		} +		bgp_notify_print(peer, &bgp_notify, "sending"); + +		if (bgp_notify.data) { +			XFREE(MTYPE_TMP, bgp_notify.data); +			bgp_notify.data = NULL; +			bgp_notify.length = 0; +		} +	} + +	/* peer reset cause */ +	if (code == BGP_NOTIFY_CEASE) { +		if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) +			peer->last_reset = PEER_DOWN_USER_RESET; +		else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) +			peer->last_reset = PEER_DOWN_USER_SHUTDOWN; +		else +			peer->last_reset = PEER_DOWN_NOTIFY_SEND; +	} else +		peer->last_reset = PEER_DOWN_NOTIFY_SEND; + +	/* Call immediately. */ +	BGP_WRITE_OFF(peer->t_write); + +	bgp_write_notify(peer);  }  /* Send BGP notify packet. */ -void -bgp_notify_send (struct peer *peer, u_char code, u_char sub_code) +void bgp_notify_send(struct peer *peer, u_char code, u_char sub_code)  { -  bgp_notify_send_with_data (peer, code, sub_code, NULL, 0); +	bgp_notify_send_with_data(peer, code, sub_code, NULL, 0);  }  /* Send route refresh message to the peer. */ -void -bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, -			u_char orf_type, u_char when_to_refresh, int remove) +void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, +			    u_char orf_type, u_char when_to_refresh, int remove)  { -  struct stream *s; -  struct bgp_filter *filter; -  int orf_refresh = 0; -  iana_afi_t pkt_afi; -  safi_t pkt_safi; - -  if (DISABLE_BGP_ANNOUNCE) -    return; - -  filter = &peer->filter[afi][safi]; - -  /* Convert AFI, SAFI to values for packet. */ -  bgp_map_afi_safi_int2iana (afi, safi, &pkt_afi, &pkt_safi); -   -  s = stream_new (BGP_MAX_PACKET_SIZE); - -  /* Make BGP update packet. */ -  if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) -    bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW); -  else -    bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD); - -  /* Encode Route Refresh message. */ -  stream_putw (s, pkt_afi); -  stream_putc (s, 0); -  stream_putc (s, pkt_safi); -  -  if (orf_type == ORF_TYPE_PREFIX -      || orf_type == ORF_TYPE_PREFIX_OLD) -    if (remove || filter->plist[FILTER_IN].plist) -      { -	u_int16_t orf_len; -	unsigned long orfp; - -	orf_refresh = 1;  -	stream_putc (s, when_to_refresh); -	stream_putc (s, orf_type); -	orfp = stream_get_endp (s); -	stream_putw (s, 0); - -	if (remove) -	  { -	    UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); -	    stream_putc (s, ORF_COMMON_PART_REMOVE_ALL); -            if (bgp_debug_neighbor_events(peer)) -	      zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d",  -			 peer->host, orf_type, -			 (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), -			 pkt_afi, pkt_safi); -	  } +	struct stream *s; +	struct bgp_filter *filter; +	int orf_refresh = 0; +	iana_afi_t pkt_afi; +	safi_t pkt_safi; + +	if (DISABLE_BGP_ANNOUNCE) +		return; + +	filter = &peer->filter[afi][safi]; + +	/* Convert AFI, SAFI to values for packet. */ +	bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + +	s = stream_new(BGP_MAX_PACKET_SIZE); + +	/* Make BGP update packet. */ +	if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) +		bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_NEW);  	else -	  { -	    SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); -	    prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, -				  ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, -				  ORF_COMMON_PART_DENY); -            if (bgp_debug_neighbor_events(peer)) -	      zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d",  -			 peer->host, orf_type, -			 (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), -			 pkt_afi, pkt_safi); -	  } - -	/* Total ORF Entry Len. */ -	orf_len = stream_get_endp (s) - orfp - 2; -	stream_putw_at (s, orfp, orf_len); -      } - -  /* Set packet size. */ -  (void)bgp_packet_set_size (s); - -  if (bgp_debug_neighbor_events(peer)) -    { -      if (! orf_refresh) -	zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d",  -		   peer->host, pkt_afi, pkt_safi); -    } - -  /* Add packet to the peer. */ -  bgp_packet_add (peer, s); - -  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +		bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_OLD); + +	/* Encode Route Refresh message. */ +	stream_putw(s, pkt_afi); +	stream_putc(s, 0); +	stream_putc(s, pkt_safi); + +	if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) +		if (remove || filter->plist[FILTER_IN].plist) { +			u_int16_t orf_len; +			unsigned long orfp; + +			orf_refresh = 1; +			stream_putc(s, when_to_refresh); +			stream_putc(s, orf_type); +			orfp = stream_get_endp(s); +			stream_putw(s, 0); + +			if (remove) { +				UNSET_FLAG(peer->af_sflags[afi][safi], +					   PEER_STATUS_ORF_PREFIX_SEND); +				stream_putc(s, ORF_COMMON_PART_REMOVE_ALL); +				if (bgp_debug_neighbor_events(peer)) +					zlog_debug( +						"%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", +						peer->host, orf_type, +						(when_to_refresh == REFRESH_DEFER +							 ? "defer" +							 : "immediate"), +						pkt_afi, pkt_safi); +			} else { +				SET_FLAG(peer->af_sflags[afi][safi], +					 PEER_STATUS_ORF_PREFIX_SEND); +				prefix_bgp_orf_entry( +					s, filter->plist[FILTER_IN].plist, +					ORF_COMMON_PART_ADD, +					ORF_COMMON_PART_PERMIT, +					ORF_COMMON_PART_DENY); +				if (bgp_debug_neighbor_events(peer)) +					zlog_debug( +						"%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", +						peer->host, orf_type, +						(when_to_refresh == REFRESH_DEFER +							 ? "defer" +							 : "immediate"), +						pkt_afi, pkt_safi); +			} + +			/* Total ORF Entry Len. */ +			orf_len = stream_get_endp(s) - orfp - 2; +			stream_putw_at(s, orfp, orf_len); +		} + +	/* Set packet size. */ +	(void)bgp_packet_set_size(s); + +	if (bgp_debug_neighbor_events(peer)) { +		if (!orf_refresh) +			zlog_debug("%s sending REFRESH_REQ for afi/safi: %d/%d", +				   peer->host, pkt_afi, pkt_safi); +	} + +	/* Add packet to the peer. */ +	bgp_packet_add(peer, s); + +	BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd);  }  /* Send capability message to the peer. */ -void -bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, -		     int capability_code, int action) +void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, +			 int capability_code, int action)  { -  struct stream *s; -  iana_afi_t pkt_afi; -  safi_t pkt_safi; +	struct stream *s; +	iana_afi_t pkt_afi; +	safi_t pkt_safi; + +	/* Convert AFI, SAFI to values for packet. */ +	bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + +	s = stream_new(BGP_MAX_PACKET_SIZE); + +	/* Make BGP update packet. */ +	bgp_packet_set_marker(s, BGP_MSG_CAPABILITY); + +	/* Encode MP_EXT capability. */ +	if (capability_code == CAPABILITY_CODE_MP) { +		stream_putc(s, action); +		stream_putc(s, CAPABILITY_CODE_MP); +		stream_putc(s, CAPABILITY_CODE_MP_LEN); +		stream_putw(s, pkt_afi); +		stream_putc(s, 0); +		stream_putc(s, pkt_safi); + +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug( +				"%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", +				peer->host, +				action == CAPABILITY_ACTION_SET ? "Advertising" +								: "Removing", +				pkt_afi, pkt_safi); +	} + +	/* Set packet size. */ +	(void)bgp_packet_set_size(s); -  /* Convert AFI, SAFI to values for packet. */ -  bgp_map_afi_safi_int2iana (afi, safi, &pkt_afi, &pkt_safi); +	/* Add packet to the peer. */ +	bgp_packet_add(peer, s); -  s = stream_new (BGP_MAX_PACKET_SIZE); +	BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd); +} -  /* Make BGP update packet. */ -  bgp_packet_set_marker (s, BGP_MSG_CAPABILITY); +/* RFC1771 6.8 Connection collision detection. */ +static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) +{ +	struct peer *peer; + +	/* Upon receipt of an OPEN message, the local system must examine +	   all of its connections that are in the OpenConfirm state.  A BGP +	   speaker may also examine connections in an OpenSent state if it +	   knows the BGP Identifier of the peer by means outside of the +	   protocol.  If among these connections there is a connection to a +	   remote BGP speaker whose BGP Identifier equals the one in the +	   OPEN message, then the local system performs the following +	   collision resolution procedure: */ + +	if ((peer = new->doppelganger) != NULL) { +		/* Do not accept the new connection in Established or Clearing +		 * states. +		 * Note that a peer GR is handled by closing the existing +		 * connection +		 * upon receipt of new one. +		 */ +		if (peer->status == Established || peer->status == Clearing) { +			bgp_notify_send(new, BGP_NOTIFY_CEASE, +					BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); +			return (-1); +		} else if ((peer->status == OpenConfirm) +			   || (peer->status == OpenSent)) { +			/* 1. The BGP Identifier of the local system is compared +			   to +			   the BGP Identifier of the remote system (as specified +			   in +			   the OPEN message). */ + +			if (ntohl(peer->local_id.s_addr) +			    < ntohl(remote_id.s_addr)) +				if (!CHECK_FLAG(peer->sflags, +						PEER_STATUS_ACCEPT_PEER)) { +					/* 2. If the value of the local BGP +					   Identifier is less +					   than the remote one, the local system +					   closes BGP +					   connection that already exists (the +					   one that is +					   already in the OpenConfirm state), +					   and accepts BGP +					   connection initiated by the remote +					   system. */ +					bgp_notify_send( +						peer, BGP_NOTIFY_CEASE, +						BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); +					return 1; +				} else { +					bgp_notify_send( +						new, BGP_NOTIFY_CEASE, +						BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); +					return -1; +				} +			else { +				/* 3. Otherwise, the local system closes newly +				   created +				   BGP connection (the one associated with the +				   newly +				   received OPEN message), and continues to use +				   the +				   existing one (the one that is already in the +				   OpenConfirm state). */ +				if (CHECK_FLAG(peer->sflags, +					       PEER_STATUS_ACCEPT_PEER)) { +					bgp_notify_send( +						peer, BGP_NOTIFY_CEASE, +						BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); +					return 1; +				} else { +					bgp_notify_send( +						new, BGP_NOTIFY_CEASE, +						BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); +					return -1; +				} +			} +		} +	} +	return 0; +} -  /* Encode MP_EXT capability. */ -  if (capability_code == CAPABILITY_CODE_MP) -    { -      stream_putc (s, action); -      stream_putc (s, CAPABILITY_CODE_MP); -      stream_putc (s, CAPABILITY_CODE_MP_LEN); -      stream_putw (s, pkt_afi); -      stream_putc (s, 0); -      stream_putc (s, pkt_safi); +static int bgp_open_receive(struct peer *peer, bgp_size_t size) +{ +	int ret; +	u_char version; +	u_char optlen; +	u_int16_t holdtime; +	u_int16_t send_holdtime; +	as_t remote_as; +	as_t as4 = 0; +	struct in_addr remote_id; +	int mp_capability; +	u_int8_t notify_data_remote_as[2]; +	u_int8_t notify_data_remote_as4[4]; +	u_int8_t notify_data_remote_id[4]; +	u_int16_t *holdtime_ptr; + +	/* Parse open packet. */ +	version = stream_getc(peer->ibuf); +	memcpy(notify_data_remote_as, stream_pnt(peer->ibuf), 2); +	remote_as = stream_getw(peer->ibuf); +	holdtime_ptr = (u_int16_t *)stream_pnt(peer->ibuf); +	holdtime = stream_getw(peer->ibuf); +	memcpy(notify_data_remote_id, stream_pnt(peer->ibuf), 4); +	remote_id.s_addr = stream_get_ipv4(peer->ibuf); + +	/* Receive OPEN message log  */ +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug( +			"%s rcv OPEN, version %d, remote-as (in open) %u," +			" holdtime %d, id %s", +			peer->host, version, remote_as, holdtime, +			inet_ntoa(remote_id)); + +	/* BEGIN to read the capability here, but dont do it yet */ +	mp_capability = 0; +	optlen = stream_getc(peer->ibuf); + +	if (optlen != 0) { +		/* If not enough bytes, it is an error. */ +		if (STREAM_READABLE(peer->ibuf) < optlen) { +			bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, +					BGP_NOTIFY_OPEN_MALFORMED_ATTR); +			return -1; +		} -      if (bgp_debug_neighbor_events(peer)) -        zlog_debug ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", -		   peer->host, action == CAPABILITY_ACTION_SET ? -		   "Advertising" : "Removing", pkt_afi, pkt_safi); -    } +		/* We need the as4 capability value *right now* because +		 * if it is there, we have not got the remote_as yet, and +		 * without +		 * that we do not know which peer is connecting to us now. +		 */ +		as4 = peek_for_as4_capability(peer, optlen); +		memcpy(notify_data_remote_as4, &as4, 4); +	} -  /* Set packet size. */ -  (void)bgp_packet_set_size (s); +	/* Just in case we have a silly peer who sends AS4 capability set to 0 +	 */ +	if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && !as4) { +		zlog_err("%s bad OPEN, got AS4 capability, but AS4 set to 0", +			 peer->host); +		bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +					  BGP_NOTIFY_OPEN_BAD_PEER_AS, +					  notify_data_remote_as4, 4); +		return -1; +	} -  /* Add packet to the peer. */ -  bgp_packet_add (peer, s); +	if (remote_as == BGP_AS_TRANS) { +		/* Take the AS4 from the capability.  We must have received the +		 * capability now!  Otherwise we have a asn16 peer who uses +		 * BGP_AS_TRANS, for some unknown reason. +		 */ +		if (as4 == BGP_AS_TRANS) { +			zlog_err( +				"%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", +				peer->host); +			bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +						  BGP_NOTIFY_OPEN_BAD_PEER_AS, +						  notify_data_remote_as4, 4); +			return -1; +		} -  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); -} +		if (!as4 && BGP_DEBUG(as4, AS4)) +			zlog_debug( +				"%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." +				" Odd, but proceeding.", +				peer->host); +		else if (as4 < BGP_AS_MAX && BGP_DEBUG(as4, AS4)) +			zlog_debug( +				"%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits " +				"in 2-bytes, very odd peer.", +				peer->host, as4); +		if (as4) +			remote_as = as4; +	} else { +		/* We may have a partner with AS4 who has an asno < BGP_AS_MAX +		 */ +		/* If we have got the capability, peer->as4cap must match +		 * remote_as */ +		if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) +		    && as4 != remote_as) { +			/* raise error, log this, close session */ +			zlog_err( +				"%s bad OPEN, got AS4 capability, but remote_as %u" +				" mismatch with 16bit 'myasn' %u in open", +				peer->host, as4, remote_as); +			bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +						  BGP_NOTIFY_OPEN_BAD_PEER_AS, +						  notify_data_remote_as4, 4); +			return -1; +		} +	} -/* RFC1771 6.8 Connection collision detection. */ -static int -bgp_collision_detect (struct peer *new, struct in_addr remote_id) -{ -  struct peer *peer; - -  /* Upon receipt of an OPEN message, the local system must examine -     all of its connections that are in the OpenConfirm state.  A BGP -     speaker may also examine connections in an OpenSent state if it -     knows the BGP Identifier of the peer by means outside of the -     protocol.  If among these connections there is a connection to a -     remote BGP speaker whose BGP Identifier equals the one in the -     OPEN message, then the local system performs the following -     collision resolution procedure: */ - -  if ((peer = new->doppelganger) != NULL) -    { -      /* Do not accept the new connection in Established or Clearing states. -       * Note that a peer GR is handled by closing the existing connection -       * upon receipt of new one. -       */ -      if (peer->status == Established || peer->status == Clearing) -        { -          bgp_notify_send (new, BGP_NOTIFY_CEASE, -                           BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); -          return (-1); -        } -      else if ((peer->status == OpenConfirm) || (peer->status == OpenSent)) -	{ -	  /* 1. The BGP Identifier of the local system is compared to -	     the BGP Identifier of the remote system (as specified in -	     the OPEN message). */ - -	  if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) -	    if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) -	      { -		/* 2. If the value of the local BGP Identifier is less -		   than the remote one, the local system closes BGP -		   connection that already exists (the one that is -		   already in the OpenConfirm state), and accepts BGP -		   connection initiated by the remote system. */ -		bgp_notify_send (peer, BGP_NOTIFY_CEASE, -				 BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); -		return 1; -	      } -	    else -	      { -		bgp_notify_send (new, BGP_NOTIFY_CEASE, -			         BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); +	/* remote router-id check. */ +	if (remote_id.s_addr == 0 || IPV4_CLASS_DE(ntohl(remote_id.s_addr)) +	    || ntohl(peer->local_id.s_addr) == ntohl(remote_id.s_addr)) { +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s bad OPEN, wrong router identifier %s", +				   peer->host, inet_ntoa(remote_id)); +		bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +					  BGP_NOTIFY_OPEN_BAD_BGP_IDENT, +					  notify_data_remote_id, 4); +		return -1; +	} + +	/* Set remote router-id */ +	peer->remote_id = remote_id; + +	/* Peer BGP version check. */ +	if (version != BGP_VERSION_4) { +		u_int16_t maxver = htons(BGP_VERSION_4); +		/* XXX this reply may not be correct if version < 4  XXX */ +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug( +				"%s bad protocol version, remote requested %d, local request %d", +				peer->host, version, BGP_VERSION_4); +		/* Data must be in network byte order here */ +		bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +					  BGP_NOTIFY_OPEN_UNSUP_VERSION, +					  (u_int8_t *)&maxver, 2); +		return -1; +	} + +	/* Check neighbor as number. */ +	if (peer->as_type == AS_UNSPECIFIED) { +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug( +				"%s bad OPEN, remote AS is unspecified currently", +				peer->host); +		bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +					  BGP_NOTIFY_OPEN_BAD_PEER_AS, +					  notify_data_remote_as, 2);  		return -1; -	      } -	  else -	    { -	      /* 3. Otherwise, the local system closes newly created -		 BGP connection (the one associated with the newly -		 received OPEN message), and continues to use the -		 existing one (the one that is already in the -		 OpenConfirm state). */ -	      if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) -		{ -		  bgp_notify_send (peer, BGP_NOTIFY_CEASE, -				   BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); -		  return 1; +	} else if (peer->as_type == AS_INTERNAL) { +		if (remote_as != peer->bgp->as) { +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug( +					"%s bad OPEN, remote AS is %u, internal specified", +					peer->host, remote_as); +			bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +						  BGP_NOTIFY_OPEN_BAD_PEER_AS, +						  notify_data_remote_as, 2); +			return -1;  		} -	      else -		{ -		  bgp_notify_send (new, BGP_NOTIFY_CEASE, -				   BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); -		  return -1; +		peer->as = peer->local_as; +	} else if (peer->as_type == AS_EXTERNAL) { +		if (remote_as == peer->bgp->as) { +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug( +					"%s bad OPEN, remote AS is %u, external specified", +					peer->host, remote_as); +			bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +						  BGP_NOTIFY_OPEN_BAD_PEER_AS, +						  notify_data_remote_as, 2); +			return -1;  		} -	    } +		peer->as = remote_as; +	} else if ((peer->as_type == AS_SPECIFIED) && (remote_as != peer->as)) { +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s bad OPEN, remote AS is %u, expected %u", +				   peer->host, remote_as, peer->as); +		bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +					  BGP_NOTIFY_OPEN_BAD_PEER_AS, +					  notify_data_remote_as, 2); +		return -1;  	} -    } -  return 0; -} -static int -bgp_open_receive (struct peer *peer, bgp_size_t size) -{ -  int ret; -  u_char version; -  u_char optlen; -  u_int16_t holdtime; -  u_int16_t send_holdtime; -  as_t remote_as; -  as_t as4 = 0; -  struct in_addr remote_id; -  int mp_capability; -  u_int8_t notify_data_remote_as[2]; -  u_int8_t notify_data_remote_as4[4]; -  u_int8_t notify_data_remote_id[4]; -  u_int16_t *holdtime_ptr; - -  /* Parse open packet. */ -  version = stream_getc (peer->ibuf); -  memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); -  remote_as  = stream_getw (peer->ibuf); -  holdtime_ptr = (u_int16_t *)stream_pnt (peer->ibuf); -  holdtime = stream_getw (peer->ibuf); -  memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); -  remote_id.s_addr = stream_get_ipv4 (peer->ibuf); - -  /* Receive OPEN message log  */ -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," -                " holdtime %d, id %s", -	        peer->host, version, remote_as, holdtime, -	        inet_ntoa (remote_id)); -   -  /* BEGIN to read the capability here, but dont do it yet */ -  mp_capability = 0; -  optlen = stream_getc (peer->ibuf); -   -  if (optlen != 0) -    { -      /* If not enough bytes, it is an error. */ -      if (STREAM_READABLE(peer->ibuf) < optlen) -        { -          bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, -                           BGP_NOTIFY_OPEN_MALFORMED_ATTR); -          return -1; -        } - -      /* We need the as4 capability value *right now* because -       * if it is there, we have not got the remote_as yet, and without -       * that we do not know which peer is connecting to us now. -       */  -      as4 = peek_for_as4_capability (peer, optlen); -      memcpy (notify_data_remote_as4, &as4, 4); -    } -   -  /* Just in case we have a silly peer who sends AS4 capability set to 0 */ -  if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4) -    { -      zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0", -                peer->host); -      bgp_notify_send_with_data (peer, -                                 BGP_NOTIFY_OPEN_ERR, -                                 BGP_NOTIFY_OPEN_BAD_PEER_AS, -                                 notify_data_remote_as4, 4); -      return -1; -    } -   -  if (remote_as == BGP_AS_TRANS) -    { -	  /* Take the AS4 from the capability.  We must have received the -	   * capability now!  Otherwise we have a asn16 peer who uses -	   * BGP_AS_TRANS, for some unknown reason. +	/* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST +	   calculate the value of the Hold Timer by using the smaller of its +	   configured Hold Time and the Hold Time received in the OPEN message. +	   The Hold Time MUST be either zero or at least three seconds.  An +	   implementation may reject connections on the basis of the Hold Time.  	   */ -      if (as4 == BGP_AS_TRANS) -        { -          zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", -                    peer->host); -          bgp_notify_send_with_data (peer, -                                     BGP_NOTIFY_OPEN_ERR, -                                     BGP_NOTIFY_OPEN_BAD_PEER_AS, -                                     notify_data_remote_as4, 4); -          return -1; -        } -       -      if (!as4 && BGP_DEBUG (as4, AS4)) -        zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." -                    " Odd, but proceeding.", peer->host); -      else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4)) -        zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits " -                    "in 2-bytes, very odd peer.", peer->host, as4); -      if (as4) -        remote_as = as4; -    }  -  else  -    { -      /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */ -      /* If we have got the capability, peer->as4cap must match remote_as */ -      if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) -          && as4 != remote_as) -        { -	  /* raise error, log this, close session */ -	  zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u" -	            " mismatch with 16bit 'myasn' %u in open", -	            peer->host, as4, remote_as); -          bgp_notify_send_with_data (peer, -                                     BGP_NOTIFY_OPEN_ERR, -                                     BGP_NOTIFY_OPEN_BAD_PEER_AS, -                                     notify_data_remote_as4, 4); -	  return -1; + +	if (holdtime < 3 && holdtime != 0) { +		bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, +					  BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, +					  (u_char *)holdtime_ptr, 2); +		return -1;  	} -    } - -  /* remote router-id check. */ -  if (remote_id.s_addr == 0 -      || IPV4_CLASS_DE (ntohl (remote_id.s_addr)) -      || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) -    { -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s bad OPEN, wrong router identifier %s", -		   peer->host, inet_ntoa (remote_id)); -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_OPEN_ERR,  -				 BGP_NOTIFY_OPEN_BAD_BGP_IDENT, -				 notify_data_remote_id, 4); -      return -1; -    } - -  /* Set remote router-id */ -  peer->remote_id = remote_id; - -  /* Peer BGP version check. */ -  if (version != BGP_VERSION_4) -    { -      u_int16_t maxver = htons(BGP_VERSION_4); -      /* XXX this reply may not be correct if version < 4  XXX */ -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s bad protocol version, remote requested %d, local request %d", -		   peer->host, version, BGP_VERSION_4); -      /* Data must be in network byte order here */ -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_OPEN_ERR,  -				 BGP_NOTIFY_OPEN_UNSUP_VERSION, -				 (u_int8_t *) &maxver, 2); -      return -1; -    } - -  /* Check neighbor as number. */ -  if (peer->as_type == AS_UNSPECIFIED) -    { -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug("%s bad OPEN, remote AS is unspecified currently", peer->host); -      bgp_notify_send_with_data(peer, -				BGP_NOTIFY_OPEN_ERR, -				BGP_NOTIFY_OPEN_BAD_PEER_AS, -				notify_data_remote_as, 2); -      return -1; -    } -  else if (peer->as_type == AS_INTERNAL) -    { -      if (remote_as != peer->bgp->as) -	{ -	  if (bgp_debug_neighbor_events(peer)) -	    zlog_debug ("%s bad OPEN, remote AS is %u, internal specified", -			peer->host, remote_as); -	  bgp_notify_send_with_data (peer, -				     BGP_NOTIFY_OPEN_ERR, -				     BGP_NOTIFY_OPEN_BAD_PEER_AS, -				     notify_data_remote_as, 2); -	  return -1; + +	/* From the rfc: A reasonable maximum time between KEEPALIVE messages +	   would be one third of the Hold Time interval.  KEEPALIVE messages +	   MUST NOT be sent more frequently than one per second.  An +	   implementation MAY adjust the rate at which it sends KEEPALIVE +	   messages as a function of the Hold Time interval. */ + +	if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)) +		send_holdtime = peer->holdtime; +	else +		send_holdtime = peer->bgp->default_holdtime; + +	if (holdtime < send_holdtime) +		peer->v_holdtime = holdtime; +	else +		peer->v_holdtime = send_holdtime; + +	if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)) +		peer->v_keepalive = peer->keepalive; +	else +		peer->v_keepalive = peer->v_holdtime / 3; + +	/* Open option part parse. */ +	if (optlen != 0) { +		if ((ret = bgp_open_option_parse(peer, optlen, &mp_capability)) +		    < 0) +			return ret; +	} else { +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s rcvd OPEN w/ OPTION parameter len: 0", +				   peer->host);  	} -      peer->as = peer->local_as; -    } -  else if (peer->as_type == AS_EXTERNAL) -    { -      if (remote_as == peer->bgp->as) -	{ -	  if (bgp_debug_neighbor_events(peer)) -	    zlog_debug ("%s bad OPEN, remote AS is %u, external specified", -			peer->host, remote_as); -	  bgp_notify_send_with_data (peer, -				     BGP_NOTIFY_OPEN_ERR, -				     BGP_NOTIFY_OPEN_BAD_PEER_AS, -				     notify_data_remote_as, 2); -	  return -1; + +	/* +	 * Assume that the peer supports the locally configured set of +	 * AFI/SAFIs if the peer did not send us any Mulitiprotocol +	 * capabilities, or if 'override-capability' is configured. +	 */ +	if (!mp_capability +	    || CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { +		peer->afc_nego[AFI_IP][SAFI_UNICAST] = +			peer->afc[AFI_IP][SAFI_UNICAST]; +		peer->afc_nego[AFI_IP][SAFI_MULTICAST] = +			peer->afc[AFI_IP][SAFI_MULTICAST]; +		peer->afc_nego[AFI_IP6][SAFI_UNICAST] = +			peer->afc[AFI_IP6][SAFI_UNICAST]; +		peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = +			peer->afc[AFI_IP6][SAFI_MULTICAST];  	} -      peer->as = remote_as; -    } -  else if ((peer->as_type == AS_SPECIFIED) && (remote_as != peer->as)) -    { -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", -		    peer->host, remote_as, peer->as); -      bgp_notify_send_with_data (peer, -				 BGP_NOTIFY_OPEN_ERR, -				 BGP_NOTIFY_OPEN_BAD_PEER_AS, -				 notify_data_remote_as, 2); -      return -1; -    } - -  /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST -     calculate the value of the Hold Timer by using the smaller of its -     configured Hold Time and the Hold Time received in the OPEN message. -     The Hold Time MUST be either zero or at least three seconds.  An -     implementation may reject connections on the basis of the Hold Time. */ - -  if (holdtime < 3 && holdtime != 0) -    { -      bgp_notify_send_with_data (peer, -		                 BGP_NOTIFY_OPEN_ERR, -		                 BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, -                                 (u_char *)holdtime_ptr, 2); -      return -1; -    } -     -  /* From the rfc: A reasonable maximum time between KEEPALIVE messages -     would be one third of the Hold Time interval.  KEEPALIVE messages -     MUST NOT be sent more frequently than one per second.  An -     implementation MAY adjust the rate at which it sends KEEPALIVE -     messages as a function of the Hold Time interval. */ - -  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) -    send_holdtime = peer->holdtime; -  else -    send_holdtime = peer->bgp->default_holdtime; - -  if (holdtime < send_holdtime) -    peer->v_holdtime = holdtime; -  else -    peer->v_holdtime = send_holdtime; - -  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) -    peer->v_keepalive = peer->keepalive; -  else -    peer->v_keepalive = peer->v_holdtime / 3; - -  /* Open option part parse. */ -  if (optlen != 0)  -    { -      if ((ret = bgp_open_option_parse (peer, optlen, &mp_capability)) < 0) -	return ret; -    } -  else -    { -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0", -		   peer->host); -    } - -  /*  -   * Assume that the peer supports the locally configured set of -   * AFI/SAFIs if the peer did not send us any Mulitiprotocol -   * capabilities, or if 'override-capability' is configured. -   */ -  if (! mp_capability || -      CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) -    { -      peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; -      peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; -      peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; -      peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; -    } - -  /* When collision is detected and this peer is closed.  Retrun -     immidiately. */ -  ret = bgp_collision_detect (peer, remote_id); -  if (ret < 0) -    return ret; - -  /* Get sockname. */ -  if ((ret = bgp_getsockname (peer)) < 0) -    { -      zlog_err("%s: bgp_getsockname() failed for peer: %s", __FUNCTION__, -	       peer->host); -      return (ret); -    } - -  /* Verify valid local address present based on negotiated address-families. */ -  if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || -      peer->afc_nego[AFI_IP][SAFI_MULTICAST] || -      peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || -      peer->afc_nego[AFI_IP][SAFI_ENCAP]) -    { -      if (!peer->nexthop.v4.s_addr) -        { -#if defined (HAVE_CUMULUS) -          zlog_err ("%s: No local IPv4 addr resetting connection, fd %d", -                    peer->host, peer->fd); -          bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); -          return -1; + +	/* When collision is detected and this peer is closed.  Retrun +	   immidiately. */ +	ret = bgp_collision_detect(peer, remote_id); +	if (ret < 0) +		return ret; + +	/* Get sockname. */ +	if ((ret = bgp_getsockname(peer)) < 0) { +		zlog_err("%s: bgp_getsockname() failed for peer: %s", +			 __FUNCTION__, peer->host); +		return (ret); +	} + +	/* Verify valid local address present based on negotiated +	 * address-families. */ +	if (peer->afc_nego[AFI_IP][SAFI_UNICAST] +	    || peer->afc_nego[AFI_IP][SAFI_MULTICAST] +	    || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] +	    || peer->afc_nego[AFI_IP][SAFI_ENCAP]) { +		if (!peer->nexthop.v4.s_addr) { +#if defined(HAVE_CUMULUS) +			zlog_err( +				"%s: No local IPv4 addr resetting connection, fd %d", +				peer->host, peer->fd); +			bgp_notify_send(peer, BGP_NOTIFY_CEASE, +					BGP_NOTIFY_SUBCODE_UNSPECIFIC); +			return -1;  #endif -        } -    } -  if (peer->afc_nego[AFI_IP6][SAFI_UNICAST] || -      peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || -      peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || -      peer->afc_nego[AFI_IP6][SAFI_ENCAP]) -    { -      if (IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_global)) -        { -#if defined (HAVE_CUMULUS) -          zlog_err ("%s: No local IPv6 addr resetting connection, fd %d", -                    peer->host, peer->fd); -          bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); -          return -1; +		} +	} +	if (peer->afc_nego[AFI_IP6][SAFI_UNICAST] +	    || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] +	    || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] +	    || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) { +		if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global)) { +#if defined(HAVE_CUMULUS) +			zlog_err( +				"%s: No local IPv6 addr resetting connection, fd %d", +				peer->host, peer->fd); +			bgp_notify_send(peer, BGP_NOTIFY_CEASE, +					BGP_NOTIFY_SUBCODE_UNSPECIFIC); +			return -1;  #endif -        } -    } -  peer->rtt = sockopt_tcp_rtt (peer->fd); - -  if ((ret = bgp_event_update(peer, Receive_OPEN_message)) < 0) -    { -      zlog_err("%s: BGP event update failed for peer: %s", __FUNCTION__, -	       peer->host); -      /* DD: bgp send notify and reset state */ -      return (ret); -    } - -  peer->packet_size = 0; -  if (peer->ibuf) -    stream_reset (peer->ibuf); - -  return 0; +		} +	} +	peer->rtt = sockopt_tcp_rtt(peer->fd); + +	if ((ret = bgp_event_update(peer, Receive_OPEN_message)) < 0) { +		zlog_err("%s: BGP event update failed for peer: %s", +			 __FUNCTION__, peer->host); +		/* DD: bgp send notify and reset state */ +		return (ret); +	} + +	peer->packet_size = 0; +	if (peer->ibuf) +		stream_reset(peer->ibuf); + +	return 0;  } -/* Called when there is a change in the EOR(implicit or explicit) status of a peer. +/* Called when there is a change in the EOR(implicit or explicit) status of a +   peer.     Ends the update-delay if all expected peers are done with EORs. */ -void -bgp_check_update_delay(struct bgp *bgp) +void bgp_check_update_delay(struct bgp *bgp)  { -  struct listnode *node, *nnode; -  struct peer *peer = NULL; - -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("Checking update delay, T: %d R: %d I:%d E: %d", bgp->established, -                bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors); - -  if (bgp->established <= -      bgp->restarted_peers + bgp->implicit_eors + bgp->explicit_eors) -    { -      /* This is an extra sanity check to make sure we wait for all the -         eligible configured peers. This check is performed if establish wait -         timer is on, or establish wait option is not given with the -         update-delay command */ -      if (bgp->t_establish_wait || -          (bgp->v_establish_wait == bgp->v_update_delay)) -        for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) -          { -            if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) -                && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) -                && !peer->update_delay_over) -              { -                if (bgp_debug_neighbor_events(peer)) -                  zlog_debug (" Peer %s pending, continuing read-only mode", -                              peer->host); -                return; -              } -          } - -      zlog_info ("Update delay ended, restarted: %d, EORs implicit: %d, explicit: %d", -                 bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors); -      bgp_update_delay_end(bgp); -    } +	struct listnode *node, *nnode; +	struct peer *peer = NULL; + +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug("Checking update delay, T: %d R: %d I:%d E: %d", +			   bgp->established, bgp->restarted_peers, +			   bgp->implicit_eors, bgp->explicit_eors); + +	if (bgp->established +	    <= bgp->restarted_peers + bgp->implicit_eors + bgp->explicit_eors) { +		/* This is an extra sanity check to make sure we wait for all +		   the +		   eligible configured peers. This check is performed if +		   establish wait +		   timer is on, or establish wait option is not given with the +		   update-delay command */ +		if (bgp->t_establish_wait +		    || (bgp->v_establish_wait == bgp->v_update_delay)) +			for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { +				if (CHECK_FLAG(peer->flags, +					       PEER_FLAG_CONFIG_NODE) +				    && !CHECK_FLAG(peer->flags, +						   PEER_FLAG_SHUTDOWN) +				    && !peer->update_delay_over) { +					if (bgp_debug_neighbor_events(peer)) +						zlog_debug( +							" Peer %s pending, continuing read-only mode", +							peer->host); +					return; +				} +			} + +		zlog_info( +			"Update delay ended, restarted: %d, EORs implicit: %d, explicit: %d", +			bgp->restarted_peers, bgp->implicit_eors, +			bgp->explicit_eors); +		bgp_update_delay_end(bgp); +	}  }  /* Called if peer is known to have restarted. The restart-state bit in     Graceful-Restart capability is used for that */ -void -bgp_update_restarted_peers (struct peer *peer) +void bgp_update_restarted_peers(struct peer *peer)  { -  if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */ -  if (peer->update_delay_over) return; /* This peer has already been considered */ - -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("Peer %s: Checking restarted", peer->host); - -  if (peer->status == Established) -    { -      peer->update_delay_over = 1; -      peer->bgp->restarted_peers++; -      bgp_check_update_delay(peer->bgp); -    } +	if (!bgp_update_delay_active(peer->bgp)) +		return; /* BGP update delay has ended */ +	if (peer->update_delay_over) +		return; /* This peer has already been considered */ + +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug("Peer %s: Checking restarted", peer->host); + +	if (peer->status == Established) { +		peer->update_delay_over = 1; +		peer->bgp->restarted_peers++; +		bgp_check_update_delay(peer->bgp); +	}  }  /* Called as peer receives a keep-alive. Determines if this occurence can be     taken as an implicit EOR for this peer.     NOTE: The very first keep-alive after the Established state of a peer is -         considered implicit EOR for the update-delay purposes */ -void -bgp_update_implicit_eors (struct peer *peer) +	 considered implicit EOR for the update-delay purposes */ +void bgp_update_implicit_eors(struct peer *peer)  { -  if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */ -  if (peer->update_delay_over) return; /* This peer has already been considered */ - -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("Peer %s: Checking implicit EORs", peer->host); - -  if (peer->status == Established) -    { -      peer->update_delay_over = 1; -      peer->bgp->implicit_eors++; -      bgp_check_update_delay(peer->bgp); -    } +	if (!bgp_update_delay_active(peer->bgp)) +		return; /* BGP update delay has ended */ +	if (peer->update_delay_over) +		return; /* This peer has already been considered */ + +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug("Peer %s: Checking implicit EORs", peer->host); + +	if (peer->status == Established) { +		peer->update_delay_over = 1; +		peer->bgp->implicit_eors++; +		bgp_check_update_delay(peer->bgp); +	}  }  /* Should be called only when there is a change in the EOR_RECEIVED status     for any afi/safi on a peer */ -static void -bgp_update_explicit_eors (struct peer *peer) +static void bgp_update_explicit_eors(struct peer *peer)  { -  afi_t afi; -  safi_t safi; - -  if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */ -  if (peer->update_delay_over) return; /* This peer has already been considered */ - -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("Peer %s: Checking explicit EORs", peer->host); - -  for (afi = AFI_IP; afi < AFI_MAX; afi++) -    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) -      { -        if (peer->afc_nego[afi][safi] && -            !CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) -          { -            if (bgp_debug_neighbor_events(peer)) -              zlog_debug ("   afi %d safi %d didnt receive EOR", afi, safi); -            return; -          } -      } - -  peer->update_delay_over = 1; -  peer->bgp->explicit_eors++; -  bgp_check_update_delay(peer->bgp); +	afi_t afi; +	safi_t safi; + +	if (!bgp_update_delay_active(peer->bgp)) +		return; /* BGP update delay has ended */ +	if (peer->update_delay_over) +		return; /* This peer has already been considered */ + +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug("Peer %s: Checking explicit EORs", peer->host); + +	for (afi = AFI_IP; afi < AFI_MAX; afi++) +		for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { +			if (peer->afc_nego[afi][safi] +			    && !CHECK_FLAG(peer->af_sflags[afi][safi], +					   PEER_STATUS_EOR_RECEIVED)) { +				if (bgp_debug_neighbor_events(peer)) +					zlog_debug( +						"   afi %d safi %d didnt receive EOR", +						afi, safi); +				return; +			} +		} + +	peer->update_delay_over = 1; +	peer->bgp->explicit_eors++; +	bgp_check_update_delay(peer->bgp);  } -/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers  - * mp_withdraw, if set, is used to nullify attr structure on most of the calling safi function +/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers + * mp_withdraw, if set, is used to nullify attr structure on most of the calling + * safi function   * and for evpn, passed as parameter   */ -int -bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int mp_withdraw) +int bgp_nlri_parse(struct peer *peer, struct attr *attr, +		   struct bgp_nlri *packet, int mp_withdraw)  { -  switch (packet->safi) -    { -      case SAFI_UNICAST: -      case SAFI_MULTICAST: -        return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet); -      case SAFI_MPLS_VPN: -        return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet); -      case SAFI_EVPN: -        return bgp_nlri_parse_evpn (peer, attr, packet, mp_withdraw); -    } -  return -1; +	switch (packet->safi) { +	case SAFI_UNICAST: +	case SAFI_MULTICAST: +		return bgp_nlri_parse_ip(peer, mp_withdraw ? NULL : attr, +					 packet); +	case SAFI_MPLS_VPN: +		return bgp_nlri_parse_vpn(peer, mp_withdraw ? NULL : attr, +					  packet); +	case SAFI_EVPN: +		return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw); +	} +	return -1;  }  /* Parse BGP Update packet and make attribute object. */ -static int -bgp_update_receive (struct peer *peer, bgp_size_t size) +static int bgp_update_receive(struct peer *peer, bgp_size_t size)  { -  int ret, nlri_ret; -  u_char *end; -  struct stream *s; -  struct attr attr; -  struct attr_extra extra; -  bgp_size_t attribute_len; -  bgp_size_t update_len; -  bgp_size_t withdraw_len; - -  enum NLRI_TYPES { -    NLRI_UPDATE, -    NLRI_WITHDRAW, -    NLRI_MP_UPDATE, -    NLRI_MP_WITHDRAW, -    NLRI_TYPE_MAX -  }; -  struct bgp_nlri nlris[NLRI_TYPE_MAX]; - -  /* Status must be Established. */ -  if (peer->status != Established)  -    { -      zlog_err ("%s [FSM] Update packet received under status %s", -		peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); -      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); -      return -1; -    } - -  /* Set initial values. */ -  memset (&attr, 0, sizeof (struct attr)); -  memset (&extra, 0, sizeof (struct attr_extra)); -  memset (&nlris, 0, sizeof (nlris)); -  attr.extra = &extra; -  memset (peer->rcvd_attr_str, 0, BUFSIZ); -  peer->rcvd_attr_printed = 0; - -  s = peer->ibuf; -  end = stream_pnt (s) + size; - -  /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute -     Length is too large (i.e., if Unfeasible Routes Length + Total -     Attribute Length + 23 exceeds the message Length), then the Error -     Subcode is set to Malformed Attribute List.  */ -  if (stream_pnt (s) + 2 > end) -    { -      zlog_err ("%s [Error] Update packet error" -		" (packet length is short for unfeasible length)", -		peer->host); -      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_MAL_ATTR); -      return -1; -    } - -  /* Unfeasible Route Length. */ -  withdraw_len = stream_getw (s); - -  /* Unfeasible Route Length check. */ -  if (stream_pnt (s) + withdraw_len > end) -    { -      zlog_err ("%s [Error] Update packet error" -		" (packet unfeasible length overflow %d)", -		peer->host, withdraw_len); -      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_MAL_ATTR); -      return -1; -    } - -  /* Unfeasible Route packet format check. */ -  if (withdraw_len > 0) -    { -      nlris[NLRI_WITHDRAW].afi = AFI_IP; -      nlris[NLRI_WITHDRAW].safi = SAFI_UNICAST; -      nlris[NLRI_WITHDRAW].nlri = stream_pnt (s); -      nlris[NLRI_WITHDRAW].length = withdraw_len; -      stream_forward_getp (s, withdraw_len); -    } -   -  /* Attribute total length check. */ -  if (stream_pnt (s) + 2 > end) -    { -      zlog_warn ("%s [Error] Packet Error" -		 " (update packet is short for attribute length)", -		 peer->host); -      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_MAL_ATTR); -      return -1; -    } - -  /* Fetch attribute total length. */ -  attribute_len = stream_getw (s); - -  /* Attribute length check. */ -  if (stream_pnt (s) + attribute_len > end) -    { -      zlog_warn ("%s [Error] Packet Error" -		 " (update packet attribute length overflow %d)", -		 peer->host, attribute_len); -      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_MAL_ATTR); -      return -1; -    } -   -  /* Certain attribute parsing errors should not be considered bad enough -   * to reset the session for, most particularly any partial/optional -   * attributes that have 'tunneled' over speakers that don't understand -   * them. Instead we withdraw only the prefix concerned. -   *  -   * Complicates the flow a little though.. -   */ -  bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; -  /* This define morphs the update case into a withdraw when lower levels -   * have signalled an error condition where this is best. -   */ +	int ret, nlri_ret; +	u_char *end; +	struct stream *s; +	struct attr attr; +	struct attr_extra extra; +	bgp_size_t attribute_len; +	bgp_size_t update_len; +	bgp_size_t withdraw_len; + +	enum NLRI_TYPES { +		NLRI_UPDATE, +		NLRI_WITHDRAW, +		NLRI_MP_UPDATE, +		NLRI_MP_WITHDRAW, +		NLRI_TYPE_MAX +	}; +	struct bgp_nlri nlris[NLRI_TYPE_MAX]; + +	/* Status must be Established. */ +	if (peer->status != Established) { +		zlog_err("%s [FSM] Update packet received under status %s", +			 peer->host, +			 lookup_msg(bgp_status_msg, peer->status, NULL)); +		bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); +		return -1; +	} + +	/* Set initial values. */ +	memset(&attr, 0, sizeof(struct attr)); +	memset(&extra, 0, sizeof(struct attr_extra)); +	memset(&nlris, 0, sizeof(nlris)); +	attr.extra = &extra; +	memset(peer->rcvd_attr_str, 0, BUFSIZ); +	peer->rcvd_attr_printed = 0; + +	s = peer->ibuf; +	end = stream_pnt(s) + size; + +	/* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute +	   Length is too large (i.e., if Unfeasible Routes Length + Total +	   Attribute Length + 23 exceeds the message Length), then the Error +	   Subcode is set to Malformed Attribute List.  */ +	if (stream_pnt(s) + 2 > end) { +		zlog_err( +			"%s [Error] Update packet error" +			" (packet length is short for unfeasible length)", +			peer->host); +		bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, +				BGP_NOTIFY_UPDATE_MAL_ATTR); +		return -1; +	} + +	/* Unfeasible Route Length. */ +	withdraw_len = stream_getw(s); + +	/* Unfeasible Route Length check. */ +	if (stream_pnt(s) + withdraw_len > end) { +		zlog_err( +			"%s [Error] Update packet error" +			" (packet unfeasible length overflow %d)", +			peer->host, withdraw_len); +		bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, +				BGP_NOTIFY_UPDATE_MAL_ATTR); +		return -1; +	} + +	/* Unfeasible Route packet format check. */ +	if (withdraw_len > 0) { +		nlris[NLRI_WITHDRAW].afi = AFI_IP; +		nlris[NLRI_WITHDRAW].safi = SAFI_UNICAST; +		nlris[NLRI_WITHDRAW].nlri = stream_pnt(s); +		nlris[NLRI_WITHDRAW].length = withdraw_len; +		stream_forward_getp(s, withdraw_len); +	} + +	/* Attribute total length check. */ +	if (stream_pnt(s) + 2 > end) { +		zlog_warn( +			"%s [Error] Packet Error" +			" (update packet is short for attribute length)", +			peer->host); +		bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, +				BGP_NOTIFY_UPDATE_MAL_ATTR); +		return -1; +	} + +	/* Fetch attribute total length. */ +	attribute_len = stream_getw(s); + +	/* Attribute length check. */ +	if (stream_pnt(s) + attribute_len > end) { +		zlog_warn( +			"%s [Error] Packet Error" +			" (update packet attribute length overflow %d)", +			peer->host, attribute_len); +		bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, +				BGP_NOTIFY_UPDATE_MAL_ATTR); +		return -1; +	} + +	/* Certain attribute parsing errors should not be considered bad enough +	 * to reset the session for, most particularly any partial/optional +	 * attributes that have 'tunneled' over speakers that don't understand +	 * them. Instead we withdraw only the prefix concerned. +	 * +	 * Complicates the flow a little though.. +	 */ +	bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; +/* This define morphs the update case into a withdraw when lower levels + * have signalled an error condition where this is best. + */  #define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL) -  /* Parse attribute when it exists. */ -  if (attribute_len) -    { -      attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len,  -			    &nlris[NLRI_MP_UPDATE], &nlris[NLRI_MP_WITHDRAW]); -      if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) -	{ -	  bgp_attr_unintern_sub (&attr); -	  return -1; +	/* Parse attribute when it exists. */ +	if (attribute_len) { +		attr_parse_ret = bgp_attr_parse(peer, &attr, attribute_len, +						&nlris[NLRI_MP_UPDATE], +						&nlris[NLRI_MP_WITHDRAW]); +		if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) { +			bgp_attr_unintern_sub(&attr); +			return -1; +		} +	} + +	/* Logging the attribute. */ +	if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW +	    || BGP_DEBUG(update, UPDATE_IN) +	    || BGP_DEBUG(update, UPDATE_PREFIX)) { +		ret = bgp_dump_attr(peer, &attr, peer->rcvd_attr_str, BUFSIZ); + +		if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) +			zlog_err( +				"%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", +				peer->host); + +		if (ret && bgp_debug_update(peer, NULL, NULL, 1)) { +			zlog_debug("%s rcvd UPDATE w/ attr: %s", peer->host, +				   peer->rcvd_attr_str); +			peer->rcvd_attr_printed = 1; +		} +	} + +	/* Network Layer Reachability Information. */ +	update_len = end - stream_pnt(s); + +	if (update_len) { +		/* Set NLRI portion to structure. */ +		nlris[NLRI_UPDATE].afi = AFI_IP; +		nlris[NLRI_UPDATE].safi = SAFI_UNICAST; +		nlris[NLRI_UPDATE].nlri = stream_pnt(s); +		nlris[NLRI_UPDATE].length = update_len; +		stream_forward_getp(s, update_len); +	} + +	if (BGP_DEBUG(update, UPDATE_IN)) +		zlog_debug("%s rcvd UPDATE wlen %d attrlen %d alen %d", +			   peer->host, withdraw_len, attribute_len, update_len); + +	/* Parse any given NLRIs */ +	for (int i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) { +		if (!nlris[i].nlri) +			continue; + +		/* NLRI is processed iff the peer if configured for the specific +		 * afi/safi */ +		if (!peer->afc[nlris[i].afi][nlris[i].safi]) { +			zlog_info( +				"%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u", +				peer->host, nlris[i].afi, nlris[i].safi); +			continue; +		} + +		/* EoR handled later */ +		if (nlris[i].length == 0) +			continue; + +		switch (i) { +		case NLRI_UPDATE: +		case NLRI_MP_UPDATE: +			nlri_ret = bgp_nlri_parse(peer, NLRI_ATTR_ARG, +						  &nlris[i], 0); +			break; +		case NLRI_WITHDRAW: +		case NLRI_MP_WITHDRAW: +			nlri_ret = bgp_nlri_parse(peer, &attr, &nlris[i], 1); +			break; +		default: +			nlri_ret = -1; +		} + +		if (nlri_ret < 0) { +			zlog_err("%s [Error] Error parsing NLRI", peer->host); +			if (peer->status == Established) +				bgp_notify_send( +					peer, BGP_NOTIFY_UPDATE_ERR, +					i <= NLRI_WITHDRAW +						? BGP_NOTIFY_UPDATE_INVAL_NETWORK +						: BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); +			bgp_attr_unintern_sub(&attr); +			return -1; +		} +	} + +	/* EoR checks +	 * +	 * Non-MP IPv4/Unicast EoR is a completely empty UPDATE +	 * and MP EoR should have only an empty MP_UNREACH +	 */ +	if (!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) { +		afi_t afi = 0; +		safi_t safi; + +		/* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already +		 * checked +		 * update and withdraw NLRI lengths are 0. +		 */ +		if (!attribute_len) { +			afi = AFI_IP; +			safi = SAFI_UNICAST; +		} else if (attr.flag & ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI) +			   && nlris[NLRI_MP_WITHDRAW].length == 0) { +			afi = nlris[NLRI_MP_WITHDRAW].afi; +			safi = nlris[NLRI_MP_WITHDRAW].safi; +		} + +		if (afi && peer->afc[afi][safi]) { +			/* End-of-RIB received */ +			if (!CHECK_FLAG(peer->af_sflags[afi][safi], +					PEER_STATUS_EOR_RECEIVED)) { +				SET_FLAG(peer->af_sflags[afi][safi], +					 PEER_STATUS_EOR_RECEIVED); +				bgp_update_explicit_eors(peer); +			} + +			/* NSF delete stale route */ +			if (peer->nsf[afi][safi]) +				bgp_clear_stale_route(peer, afi, safi); + +			if (bgp_debug_neighbor_events(peer)) { +				zlog_debug("rcvd End-of-RIB for %s from %s", +					   afi_safi_print(afi, safi), +					   peer->host); +			} +		}  	} -    } -   -  /* Logging the attribute. */ -  if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW || -      BGP_DEBUG (update, UPDATE_IN) || -      BGP_DEBUG (update, UPDATE_PREFIX)) -    { -      ret = bgp_dump_attr (peer, &attr, peer->rcvd_attr_str, BUFSIZ); -       -      if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) -        zlog_err ("%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", -                  peer->host); - -      if (ret && bgp_debug_update(peer, NULL, NULL, 1)) -        { -          zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str); -          peer->rcvd_attr_printed = 1; -        } -    } -   -  /* Network Layer Reachability Information. */ -  update_len = end - stream_pnt (s); - -  if (update_len) -    { -      /* Set NLRI portion to structure. */ -      nlris[NLRI_UPDATE].afi = AFI_IP; -      nlris[NLRI_UPDATE].safi = SAFI_UNICAST; -      nlris[NLRI_UPDATE].nlri = stream_pnt (s); -      nlris[NLRI_UPDATE].length = update_len; -      stream_forward_getp (s, update_len); -    } - -  if (BGP_DEBUG (update, UPDATE_IN)) -    zlog_debug("%s rcvd UPDATE wlen %d attrlen %d alen %d", -               peer->host, withdraw_len, attribute_len, update_len); - -  /* Parse any given NLRIs */ -  for (int i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) -    { -      if (!nlris[i].nlri) -        continue; - -      /* NLRI is processed iff the peer if configured for the specific afi/safi */ -      if (!peer->afc[nlris[i].afi][nlris[i].safi]) -        { -          zlog_info ("%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u", -                     peer->host, nlris[i].afi, nlris[i].safi); -          continue; -        } - -      /* EoR handled later */ -      if (nlris[i].length == 0) -        continue; - -      switch (i) -        { -          case NLRI_UPDATE: -          case NLRI_MP_UPDATE: -            nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i], 0); -            break; -          case NLRI_WITHDRAW: -          case NLRI_MP_WITHDRAW: -            nlri_ret = bgp_nlri_parse (peer, &attr, &nlris[i], 1); -            break; -          default: -            nlri_ret = -1; -        } - -      if (nlri_ret < 0) -        { -          zlog_err("%s [Error] Error parsing NLRI", peer->host); -          if (peer->status == Established) -            bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, -                             i <= NLRI_WITHDRAW ? BGP_NOTIFY_UPDATE_INVAL_NETWORK -                                                : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); -          bgp_attr_unintern_sub (&attr); -          return -1; -        } -    } - -  /* EoR checks -   * -   * Non-MP IPv4/Unicast EoR is a completely empty UPDATE -   * and MP EoR should have only an empty MP_UNREACH -   */ -  if (!update_len && !withdraw_len -      && nlris[NLRI_MP_UPDATE].length == 0) -    { -      afi_t afi = 0; -      safi_t safi; - -      /* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already checked -       * update and withdraw NLRI lengths are 0. -       */ -      if (!attribute_len) -        { -          afi = AFI_IP; -          safi = SAFI_UNICAST; -        } -      else if (attr.flag & ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI) -               && nlris[NLRI_MP_WITHDRAW].length == 0) -        { -          afi = nlris[NLRI_MP_WITHDRAW].afi; -          safi = nlris[NLRI_MP_WITHDRAW].safi; -        } - -      if (afi && peer->afc[afi][safi]) -        { -          /* End-of-RIB received */ -          if (!CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) -            { -              SET_FLAG (peer->af_sflags[afi][safi], -                        PEER_STATUS_EOR_RECEIVED); -              bgp_update_explicit_eors(peer); -            } - -          /* NSF delete stale route */ -          if (peer->nsf[afi][safi]) -            bgp_clear_stale_route (peer, afi, safi); - -          if (bgp_debug_neighbor_events(peer)) -            { -              zlog_debug ("rcvd End-of-RIB for %s from %s", -                          afi_safi_print (afi, safi), peer->host); -            } -        } -    } - -  /* Everything is done.  We unintern temporary structures which -     interned in bgp_attr_parse(). */ -  bgp_attr_unintern_sub (&attr); - -  /* If peering is stopped due to some reason, do not generate BGP -     event.  */ -  if (peer->status != Established) -    return 0; - -  /* Increment packet counter. */ -  peer->update_in++; -  peer->update_time = bgp_clock (); - -  /* Rearm holdtime timer */ -  BGP_TIMER_OFF (peer->t_holdtime); -  bgp_timer_set (peer); - -  return 0; + +	/* Everything is done.  We unintern temporary structures which +	   interned in bgp_attr_parse(). */ +	bgp_attr_unintern_sub(&attr); + +	/* If peering is stopped due to some reason, do not generate BGP +	   event.  */ +	if (peer->status != Established) +		return 0; + +	/* Increment packet counter. */ +	peer->update_in++; +	peer->update_time = bgp_clock(); + +	/* Rearm holdtime timer */ +	BGP_TIMER_OFF(peer->t_holdtime); +	bgp_timer_set(peer); + +	return 0;  }  /* Notify message treatment function. */ -static void -bgp_notify_receive (struct peer *peer, bgp_size_t size) +static void bgp_notify_receive(struct peer *peer, bgp_size_t size)  { -  struct bgp_notify bgp_notify; - -  if (peer->notify.data) -    { -      XFREE (MTYPE_TMP, peer->notify.data); -      peer->notify.data = NULL; -      peer->notify.length = 0; -    } - -  bgp_notify.code = stream_getc (peer->ibuf); -  bgp_notify.subcode = stream_getc (peer->ibuf); -  bgp_notify.length = size - 2; -  bgp_notify.data = NULL; - -  /* Preserv notify code and sub code. */ -  peer->notify.code = bgp_notify.code; -  peer->notify.subcode = bgp_notify.subcode; -  /* For further diagnostic record returned Data. */ -  if (bgp_notify.length) -    { -      peer->notify.length = size - 2; -      peer->notify.data = XMALLOC (MTYPE_TMP, size - 2); -      memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2); -    } - -  /* For debug */ -  { -    int i; -    int first = 0; -    char c[4]; - -    if (bgp_notify.length) -      { -	bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); -	for (i = 0; i < bgp_notify.length; i++) -	  if (first) -	    { -	      sprintf (c, " %02x", stream_getc (peer->ibuf)); -	      strcat (bgp_notify.data, c); -	    } -	  else -	    { -	      first = 1; -	      sprintf (c, "%02x", stream_getc (peer->ibuf)); -	      strcpy (bgp_notify.data, c); -	    } -	bgp_notify.raw_data = (u_char*)peer->notify.data; -      } - -    bgp_notify_print(peer, &bgp_notify, "received"); -    if (bgp_notify.data) -      { -        XFREE (MTYPE_TMP, bgp_notify.data); -        bgp_notify.data = NULL; -        bgp_notify.length = 0; -      } -  } - -  /* peer count update */ -  peer->notify_in++; - -  peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED; - -  /* We have to check for Notify with Unsupported Optional Parameter. -     in that case we fallback to open without the capability option. -     But this done in bgp_stop. We just mark it here to avoid changing -     the fsm tables.  */ -  if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && -      bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM ) -    UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); - -  BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message); +	struct bgp_notify bgp_notify; + +	if (peer->notify.data) { +		XFREE(MTYPE_TMP, peer->notify.data); +		peer->notify.data = NULL; +		peer->notify.length = 0; +	} + +	bgp_notify.code = stream_getc(peer->ibuf); +	bgp_notify.subcode = stream_getc(peer->ibuf); +	bgp_notify.length = size - 2; +	bgp_notify.data = NULL; + +	/* Preserv notify code and sub code. */ +	peer->notify.code = bgp_notify.code; +	peer->notify.subcode = bgp_notify.subcode; +	/* For further diagnostic record returned Data. */ +	if (bgp_notify.length) { +		peer->notify.length = size - 2; +		peer->notify.data = XMALLOC(MTYPE_TMP, size - 2); +		memcpy(peer->notify.data, stream_pnt(peer->ibuf), size - 2); +	} + +	/* For debug */ +	{ +		int i; +		int first = 0; +		char c[4]; + +		if (bgp_notify.length) { +			bgp_notify.data = +				XMALLOC(MTYPE_TMP, bgp_notify.length * 3); +			for (i = 0; i < bgp_notify.length; i++) +				if (first) { +					sprintf(c, " %02x", +						stream_getc(peer->ibuf)); +					strcat(bgp_notify.data, c); +				} else { +					first = 1; +					sprintf(c, "%02x", +						stream_getc(peer->ibuf)); +					strcpy(bgp_notify.data, c); +				} +			bgp_notify.raw_data = (u_char *)peer->notify.data; +		} + +		bgp_notify_print(peer, &bgp_notify, "received"); +		if (bgp_notify.data) { +			XFREE(MTYPE_TMP, bgp_notify.data); +			bgp_notify.data = NULL; +			bgp_notify.length = 0; +		} +	} + +	/* peer count update */ +	peer->notify_in++; + +	peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED; + +	/* We have to check for Notify with Unsupported Optional Parameter. +	   in that case we fallback to open without the capability option. +	   But this done in bgp_stop. We just mark it here to avoid changing +	   the fsm tables.  */ +	if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR +	    && bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) +		UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + +	BGP_EVENT_ADD(peer, Receive_NOTIFICATION_message);  }  /* Keepalive treatment function -- get keepalive send keepalive */ -static void -bgp_keepalive_receive (struct peer *peer, bgp_size_t size) +static void bgp_keepalive_receive(struct peer *peer, bgp_size_t size)  { -  if (bgp_debug_keepalive(peer)) -    zlog_debug ("%s KEEPALIVE rcvd", peer->host);  -   -  BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); +	if (bgp_debug_keepalive(peer)) +		zlog_debug("%s KEEPALIVE rcvd", peer->host); + +	BGP_EVENT_ADD(peer, Receive_KEEPALIVE_message);  }  /* Route refresh message is received. */ -static void -bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) +static void bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)  { -  iana_afi_t pkt_afi; -  afi_t afi; -  safi_t pkt_safi, safi; -  struct stream *s; -  struct peer_af *paf; -  struct update_group *updgrp; -  struct peer *updgrp_peer; - -  /* If peer does not have the capability, send notification. */ -  if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) -    { -      zlog_err ("%s [Error] BGP route refresh is not enabled", -		peer->host); -      bgp_notify_send (peer, -		       BGP_NOTIFY_HEADER_ERR, -		       BGP_NOTIFY_HEADER_BAD_MESTYPE); -      return; -    } - -  /* Status must be Established. */ -  if (peer->status != Established)  -    { -      zlog_err ("%s [Error] Route refresh packet received under status %s", -		peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); -      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); -      return; -    } - -  s = peer->ibuf; -   -  /* Parse packet. */ -  pkt_afi = stream_getw (s); -  (void)stream_getc (s); -  pkt_safi = stream_getc (s); - -  if (bgp_debug_update(peer, NULL, NULL, 0)) -    zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d", -	       peer->host, pkt_afi, pkt_safi); - -  /* Convert AFI, SAFI to internal values and check. */ -  if (bgp_map_afi_safi_iana2int (pkt_afi, pkt_safi, &afi, &safi)) -    { -      zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", -		 peer->host, pkt_afi, pkt_safi); -      return; -    } - -  if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) -    { -      u_char *end; -      u_char when_to_refresh; -      u_char orf_type; -      u_int16_t orf_len; - -      if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5) -        { -          zlog_info ("%s ORF route refresh length error", peer->host); -          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); -          return; -        } - -      when_to_refresh = stream_getc (s); -      end = stream_pnt (s) + (size - 5); - -      while ((stream_pnt (s) + 2) < end) -	{ -	  orf_type = stream_getc (s);  -	  orf_len = stream_getw (s); -	   -	  /* orf_len in bounds? */ -	  if ((stream_pnt (s) + orf_len) > end) -	    break; /* XXX: Notify instead?? */ -	  if (orf_type == ORF_TYPE_PREFIX -	      || orf_type == ORF_TYPE_PREFIX_OLD) -	    { -	      uint8_t *p_pnt = stream_pnt (s); -	      uint8_t *p_end = stream_pnt (s) + orf_len; -	      struct orf_prefix orfp; -	      u_char common = 0; -	      u_int32_t seq; -	      int psize; -	      char name[BUFSIZ]; -	      int ret = CMD_SUCCESS; - -              if (bgp_debug_neighbor_events(peer)) -		{ -		  zlog_debug ("%s rcvd Prefixlist ORF(%d) length %d", -			     peer->host, orf_type, orf_len); +	iana_afi_t pkt_afi; +	afi_t afi; +	safi_t pkt_safi, safi; +	struct stream *s; +	struct peer_af *paf; +	struct update_group *updgrp; +	struct peer *updgrp_peer; + +	/* If peer does not have the capability, send notification. */ +	if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_ADV)) { +		zlog_err("%s [Error] BGP route refresh is not enabled", +			 peer->host); +		bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR, +				BGP_NOTIFY_HEADER_BAD_MESTYPE); +		return; +	} + +	/* Status must be Established. */ +	if (peer->status != Established) { +		zlog_err( +			"%s [Error] Route refresh packet received under status %s", +			peer->host, +			lookup_msg(bgp_status_msg, peer->status, NULL)); +		bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); +		return; +	} + +	s = peer->ibuf; + +	/* Parse packet. */ +	pkt_afi = stream_getw(s); +	(void)stream_getc(s); +	pkt_safi = stream_getc(s); + +	if (bgp_debug_update(peer, NULL, NULL, 0)) +		zlog_debug("%s rcvd REFRESH_REQ for afi/safi: %d/%d", +			   peer->host, pkt_afi, pkt_safi); + +	/* Convert AFI, SAFI to internal values and check. */ +	if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { +		zlog_info( +			"%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", +			peer->host, pkt_afi, pkt_safi); +		return; +	} + +	if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) { +		u_char *end; +		u_char when_to_refresh; +		u_char orf_type; +		u_int16_t orf_len; + +		if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) +		    < 5) { +			zlog_info("%s ORF route refresh length error", +				  peer->host); +			bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); +			return;  		} -              /* we're going to read at least 1 byte of common ORF header, -               * and 7 bytes of ORF Address-filter entry from the stream -               */ -              if (orf_len < 7) -                break;  -                 -	      /* ORF prefix-list name */ -	      sprintf (name, "%s.%d.%d", peer->host, afi, safi); - -	      while (p_pnt < p_end) -		{ -                  /* If the ORF entry is malformed, want to read as much of it -                   * as possible without going beyond the bounds of the entry, -                   * to maximise debug information. -                   */ -		  int ok; -		  memset (&orfp, 0, sizeof (struct orf_prefix)); -		  common = *p_pnt++; -		  /* after ++: p_pnt <= p_end */ -		  if (common & ORF_COMMON_PART_REMOVE_ALL) -		    { -                      if (bgp_debug_neighbor_events(peer)) -			zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host); -		      prefix_bgp_orf_remove_all (afi, name); -		      break; -		    } -		  ok = ((u_int32_t)(p_end - p_pnt) >= sizeof(u_int32_t)) ; -		  if (ok) -		    { -		      memcpy (&seq, p_pnt, sizeof (u_int32_t)); -                      p_pnt += sizeof (u_int32_t); -                      orfp.seq = ntohl (seq); -		    } -		  else -		    p_pnt = p_end ; - -		  if ((ok = (p_pnt < p_end))) -		    orfp.ge = *p_pnt++ ;      /* value checked in prefix_bgp_orf_set() */ -		  if ((ok = (p_pnt < p_end))) -		    orfp.le = *p_pnt++ ;      /* value checked in prefix_bgp_orf_set() */ -		  if ((ok = (p_pnt < p_end))) -		    orfp.p.prefixlen = *p_pnt++ ; -		  orfp.p.family = afi2family (afi);   /* afi checked already  */ - -		  psize = PSIZE (orfp.p.prefixlen);   /* 0 if not ok          */ -		  if (psize > prefix_blen(&orfp.p))   /* valid for family ?   */ -		    { -		      ok = 0 ; -		      psize = prefix_blen(&orfp.p) ; -		    } -		  if (psize > (p_end - p_pnt))        /* valid for packet ?   */ -		    { -		      ok = 0 ; -		      psize = p_end - p_pnt ; -		    } - -		  if (psize > 0) -		    memcpy (&orfp.p.u.prefix, p_pnt, psize); -		  p_pnt += psize; - -                  if (bgp_debug_neighbor_events(peer)) -		    { -		      char buf[INET6_BUFSIZ]; - -		      zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s", -			         peer->host, -			         (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), -			         (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), -			         orfp.seq, -			         inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, INET6_BUFSIZ), -			         orfp.p.prefixlen, orfp.ge, orfp.le, -			         ok ? "" : " MALFORMED"); -		    } - -		  if (ok) -		    ret = prefix_bgp_orf_set (name, afi, &orfp, -				   (common & ORF_COMMON_PART_DENY ? 0 : 1 ), -				   (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); - -		  if (!ok || (ok && ret != CMD_SUCCESS)) -		    { -		      zlog_info ("%s Received misformatted prefixlist ORF." -			         " Remove All pfxlist", peer->host); -		      prefix_bgp_orf_remove_all (afi, name); -		      break; -		    } +		when_to_refresh = stream_getc(s); +		end = stream_pnt(s) + (size - 5); + +		while ((stream_pnt(s) + 2) < end) { +			orf_type = stream_getc(s); +			orf_len = stream_getw(s); + +			/* orf_len in bounds? */ +			if ((stream_pnt(s) + orf_len) > end) +				break; /* XXX: Notify instead?? */ +			if (orf_type == ORF_TYPE_PREFIX +			    || orf_type == ORF_TYPE_PREFIX_OLD) { +				uint8_t *p_pnt = stream_pnt(s); +				uint8_t *p_end = stream_pnt(s) + orf_len; +				struct orf_prefix orfp; +				u_char common = 0; +				u_int32_t seq; +				int psize; +				char name[BUFSIZ]; +				int ret = CMD_SUCCESS; + +				if (bgp_debug_neighbor_events(peer)) { +					zlog_debug( +						"%s rcvd Prefixlist ORF(%d) length %d", +						peer->host, orf_type, orf_len); +				} + +				/* we're going to read at least 1 byte of common +				 * ORF header, +				 * and 7 bytes of ORF Address-filter entry from +				 * the stream +				 */ +				if (orf_len < 7) +					break; + +				/* ORF prefix-list name */ +				sprintf(name, "%s.%d.%d", peer->host, afi, +					safi); + +				while (p_pnt < p_end) { +					/* If the ORF entry is malformed, want +					 * to read as much of it +					 * as possible without going beyond the +					 * bounds of the entry, +					 * to maximise debug information. +					 */ +					int ok; +					memset(&orfp, 0, +					       sizeof(struct orf_prefix)); +					common = *p_pnt++; +					/* after ++: p_pnt <= p_end */ +					if (common +					    & ORF_COMMON_PART_REMOVE_ALL) { +						if (bgp_debug_neighbor_events( +							    peer)) +							zlog_debug( +								"%s rcvd Remove-All pfxlist ORF request", +								peer->host); +						prefix_bgp_orf_remove_all(afi, +									  name); +						break; +					} +					ok = ((u_int32_t)(p_end - p_pnt) +					      >= sizeof(u_int32_t)); +					if (ok) { +						memcpy(&seq, p_pnt, +						       sizeof(u_int32_t)); +						p_pnt += sizeof(u_int32_t); +						orfp.seq = ntohl(seq); +					} else +						p_pnt = p_end; + +					if ((ok = (p_pnt < p_end))) +						orfp.ge = +							*p_pnt++; /* value +								     checked in +								     prefix_bgp_orf_set() +								     */ +					if ((ok = (p_pnt < p_end))) +						orfp.le = +							*p_pnt++; /* value +								     checked in +								     prefix_bgp_orf_set() +								     */ +					if ((ok = (p_pnt < p_end))) +						orfp.p.prefixlen = *p_pnt++; +					orfp.p.family = afi2family( +						afi); /* afi checked already  */ + +					psize = PSIZE( +						orfp.p.prefixlen); /* 0 if not +								      ok */ +					if (psize +					    > prefix_blen( +						      &orfp.p)) /* valid for +								   family ?   */ +					{ +						ok = 0; +						psize = prefix_blen(&orfp.p); +					} +					if (psize +					    > (p_end - p_pnt)) /* valid for +								  packet ?   */ +					{ +						ok = 0; +						psize = p_end - p_pnt; +					} + +					if (psize > 0) +						memcpy(&orfp.p.u.prefix, p_pnt, +						       psize); +					p_pnt += psize; + +					if (bgp_debug_neighbor_events(peer)) { +						char buf[INET6_BUFSIZ]; + +						zlog_debug( +							"%s rcvd %s %s seq %u %s/%d ge %d le %d%s", +							peer->host, +							(common & ORF_COMMON_PART_REMOVE +								 ? "Remove" +								 : "Add"), +							(common & ORF_COMMON_PART_DENY +								 ? "deny" +								 : "permit"), +							orfp.seq, +							inet_ntop( +								orfp.p.family, +								&orfp.p.u.prefix, +								buf, +								INET6_BUFSIZ), +							orfp.p.prefixlen, +							orfp.ge, orfp.le, +							ok ? "" : " MALFORMED"); +					} + +					if (ok) +						ret = prefix_bgp_orf_set( +							name, afi, &orfp, +							(common & ORF_COMMON_PART_DENY +								 ? 0 +								 : 1), +							(common & ORF_COMMON_PART_REMOVE +								 ? 0 +								 : 1)); + +					if (!ok || (ok && ret != CMD_SUCCESS)) { +						zlog_info( +							"%s Received misformatted prefixlist ORF." +							" Remove All pfxlist", +							peer->host); +						prefix_bgp_orf_remove_all(afi, +									  name); +						break; +					} +				} + +				peer->orf_plist[afi][safi] = +					prefix_bgp_orf_lookup(afi, name); +			} +			stream_forward_getp(s, orf_len);  		} +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s rcvd Refresh %s ORF request", peer->host, +				   when_to_refresh == REFRESH_DEFER +					   ? "Defer" +					   : "Immediate"); +		if (when_to_refresh == REFRESH_DEFER) +			return; +	} -	      peer->orf_plist[afi][safi] = prefix_bgp_orf_lookup (afi, name); -	    } -	  stream_forward_getp (s, orf_len); +	/* First update is deferred until ORF or ROUTE-REFRESH is received */ +	if (CHECK_FLAG(peer->af_sflags[afi][safi], +		       PEER_STATUS_ORF_WAIT_REFRESH)) +		UNSET_FLAG(peer->af_sflags[afi][safi], +			   PEER_STATUS_ORF_WAIT_REFRESH); + +	paf = peer_af_find(peer, afi, safi); +	if (paf && paf->subgroup) { +		if (peer->orf_plist[afi][safi]) { +			updgrp = PAF_UPDGRP(paf); +			updgrp_peer = UPDGRP_PEER(updgrp); +			updgrp_peer->orf_plist[afi][safi] = +				peer->orf_plist[afi][safi]; +		} + +		/* If the peer is configured for default-originate clear the +		 * SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will +		 * re-advertise the +		 * default +		 */ +		if (CHECK_FLAG(paf->subgroup->sflags, +			       SUBGRP_STATUS_DEFAULT_ORIGINATE)) +			UNSET_FLAG(paf->subgroup->sflags, +				   SUBGRP_STATUS_DEFAULT_ORIGINATE);  	} -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s rcvd Refresh %s ORF request", peer->host, -		   when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate"); -      if (when_to_refresh == REFRESH_DEFER) -	return; -    } - -  /* First update is deferred until ORF or ROUTE-REFRESH is received */ -  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) -    UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); - -  paf = peer_af_find (peer, afi, safi); -  if (paf && paf->subgroup) -    { -      if (peer->orf_plist[afi][safi]) -        { -          updgrp = PAF_UPDGRP(paf); -          updgrp_peer = UPDGRP_PEER(updgrp); -          updgrp_peer->orf_plist[afi][safi] = peer->orf_plist[afi][safi]; -        } - -      /* If the peer is configured for default-originate clear the -       * SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will re-advertise the -       * default -       */ -      if (CHECK_FLAG (paf->subgroup->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)) -        UNSET_FLAG (paf->subgroup->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); -    } - -  /* Perform route refreshment to the peer */ -  bgp_announce_route (peer, afi, safi); + +	/* Perform route refreshment to the peer */ +	bgp_announce_route(peer, afi, safi);  } -static int -bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) +static int bgp_capability_msg_parse(struct peer *peer, u_char *pnt, +				    bgp_size_t length)  { -  u_char *end; -  struct capability_mp_data mpc; -  struct capability_header *hdr; -  u_char action; -  iana_afi_t pkt_afi; -  afi_t afi; -  safi_t pkt_safi, safi; - -  end = pnt + length; - -  while (pnt < end) -    {       -      /* We need at least action, capability code and capability length. */ -      if (pnt + 3 > end) -        { -          zlog_info ("%s Capability length error", peer->host); -          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); -          return -1; -        } -      action = *pnt; -      hdr = (struct capability_header *)(pnt + 1); -       -      /* Action value check.  */ -      if (action != CAPABILITY_ACTION_SET -	  && action != CAPABILITY_ACTION_UNSET) -        { -          zlog_info ("%s Capability Action Value error %d", -		     peer->host, action); -          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); -          return -1; -        } - -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s CAPABILITY has action: %d, code: %u, length %u", -		   peer->host, action, hdr->code, hdr->length); - -      /* Capability length check. */ -      if ((pnt + hdr->length + 3) > end) -        { -          zlog_info ("%s Capability length error", peer->host); -          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); -          return -1; -        } - -      /* Fetch structure to the byte stream. */ -      memcpy (&mpc, pnt + 3, sizeof (struct capability_mp_data)); - -      /* We know MP Capability Code. */ -      if (hdr->code == CAPABILITY_CODE_MP) -        { -	  pkt_afi = ntohs (mpc.afi); -	  pkt_safi = mpc.safi; - -          /* Ignore capability when override-capability is set. */ -          if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) -	    continue; -           -          /* Convert AFI, SAFI to internal values. */ -          if (bgp_map_afi_safi_iana2int (pkt_afi, pkt_safi, &afi, &safi)) -            { -              if (bgp_debug_neighbor_events(peer)) -                zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid " -                            "(%u/%u)", peer->host, pkt_afi, pkt_safi); -              continue; -            } -           -	  /* Address family check.  */ -          if (bgp_debug_neighbor_events(peer)) -            zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", -                       peer->host, -                       action == CAPABILITY_ACTION_SET  -                       ? "Advertising" : "Removing", -                       pkt_afi, pkt_safi); -               -          if (action == CAPABILITY_ACTION_SET) -            { -              peer->afc_recv[afi][safi] = 1; -              if (peer->afc[afi][safi]) -                { -                  peer->afc_nego[afi][safi] = 1; -                  bgp_announce_route (peer, afi, safi); -                } -            } -          else -            { -              peer->afc_recv[afi][safi] = 0; -              peer->afc_nego[afi][safi] = 0; - -              if (peer_active_nego (peer)) -                bgp_clear_route (peer, afi, safi); -              else -                BGP_EVENT_ADD (peer, BGP_Stop); -            } -        } -      else -        { -          zlog_warn ("%s unrecognized capability code: %d - ignored", -                     peer->host, hdr->code); -        } -      pnt += hdr->length + 3; -    } -  return 0; +	u_char *end; +	struct capability_mp_data mpc; +	struct capability_header *hdr; +	u_char action; +	iana_afi_t pkt_afi; +	afi_t afi; +	safi_t pkt_safi, safi; + +	end = pnt + length; + +	while (pnt < end) { +		/* We need at least action, capability code and capability +		 * length. */ +		if (pnt + 3 > end) { +			zlog_info("%s Capability length error", peer->host); +			bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); +			return -1; +		} +		action = *pnt; +		hdr = (struct capability_header *)(pnt + 1); + +		/* Action value check.  */ +		if (action != CAPABILITY_ACTION_SET +		    && action != CAPABILITY_ACTION_UNSET) { +			zlog_info("%s Capability Action Value error %d", +				  peer->host, action); +			bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); +			return -1; +		} + +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug( +				"%s CAPABILITY has action: %d, code: %u, length %u", +				peer->host, action, hdr->code, hdr->length); + +		/* Capability length check. */ +		if ((pnt + hdr->length + 3) > end) { +			zlog_info("%s Capability length error", peer->host); +			bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); +			return -1; +		} + +		/* Fetch structure to the byte stream. */ +		memcpy(&mpc, pnt + 3, sizeof(struct capability_mp_data)); + +		/* We know MP Capability Code. */ +		if (hdr->code == CAPABILITY_CODE_MP) { +			pkt_afi = ntohs(mpc.afi); +			pkt_safi = mpc.safi; + +			/* Ignore capability when override-capability is set. */ +			if (CHECK_FLAG(peer->flags, +				       PEER_FLAG_OVERRIDE_CAPABILITY)) +				continue; + +			/* Convert AFI, SAFI to internal values. */ +			if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, +						      &safi)) { +				if (bgp_debug_neighbor_events(peer)) +					zlog_debug( +						"%s Dynamic Capability MP_EXT afi/safi invalid " +						"(%u/%u)", +						peer->host, pkt_afi, pkt_safi); +				continue; +			} + +			/* Address family check.  */ +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug( +					"%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", +					peer->host, +					action == CAPABILITY_ACTION_SET +						? "Advertising" +						: "Removing", +					pkt_afi, pkt_safi); + +			if (action == CAPABILITY_ACTION_SET) { +				peer->afc_recv[afi][safi] = 1; +				if (peer->afc[afi][safi]) { +					peer->afc_nego[afi][safi] = 1; +					bgp_announce_route(peer, afi, safi); +				} +			} else { +				peer->afc_recv[afi][safi] = 0; +				peer->afc_nego[afi][safi] = 0; + +				if (peer_active_nego(peer)) +					bgp_clear_route(peer, afi, safi); +				else +					BGP_EVENT_ADD(peer, BGP_Stop); +			} +		} else { +			zlog_warn( +				"%s unrecognized capability code: %d - ignored", +				peer->host, hdr->code); +		} +		pnt += hdr->length + 3; +	} +	return 0;  } -/* Dynamic Capability is received.  +/* Dynamic Capability is received.   *   * This is exported for unit-test purposes   */ -int -bgp_capability_receive (struct peer *peer, bgp_size_t size) +int bgp_capability_receive(struct peer *peer, bgp_size_t size)  { -  u_char *pnt; - -  /* Fetch pointer. */ -  pnt = stream_pnt (peer->ibuf); - -  if (bgp_debug_neighbor_events(peer)) -    zlog_debug ("%s rcv CAPABILITY", peer->host); - -  /* If peer does not have the capability, send notification. */ -  if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV)) -    { -      zlog_err ("%s [Error] BGP dynamic capability is not enabled", -		peer->host); -      bgp_notify_send (peer, -		       BGP_NOTIFY_HEADER_ERR, -		       BGP_NOTIFY_HEADER_BAD_MESTYPE); -      return -1; -    } - -  /* Status must be Established. */ -  if (peer->status != Established) -    { -      zlog_err ("%s [Error] Dynamic capability packet received under status %s", -                peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); -      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); -      return -1; -    } - -  /* Parse packet. */ -  return bgp_capability_msg_parse (peer, pnt, size); +	u_char *pnt; + +	/* Fetch pointer. */ +	pnt = stream_pnt(peer->ibuf); + +	if (bgp_debug_neighbor_events(peer)) +		zlog_debug("%s rcv CAPABILITY", peer->host); + +	/* If peer does not have the capability, send notification. */ +	if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) { +		zlog_err("%s [Error] BGP dynamic capability is not enabled", +			 peer->host); +		bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR, +				BGP_NOTIFY_HEADER_BAD_MESTYPE); +		return -1; +	} + +	/* Status must be Established. */ +	if (peer->status != Established) { +		zlog_err( +			"%s [Error] Dynamic capability packet received under status %s", +			peer->host, +			lookup_msg(bgp_status_msg, peer->status, NULL)); +		bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); +		return -1; +	} + +	/* Parse packet. */ +	return bgp_capability_msg_parse(peer, pnt, size);  }  /* BGP read utility function. */ -static int -bgp_read_packet (struct peer *peer) +static int bgp_read_packet(struct peer *peer)  { -  int nbytes; -  int readsize; +	int nbytes; +	int readsize; -  readsize = peer->packet_size - stream_get_endp (peer->ibuf); +	readsize = peer->packet_size - stream_get_endp(peer->ibuf); -  /* If size is zero then return. */ -  if (! readsize) -    return 0; +	/* If size is zero then return. */ +	if (!readsize) +		return 0; -  /* Read packet from fd. */ -  nbytes = stream_read_try (peer->ibuf, peer->fd, readsize); +	/* Read packet from fd. */ +	nbytes = stream_read_try(peer->ibuf, peer->fd, readsize); -  /* If read byte is smaller than zero then error occured. */ -  if (nbytes < 0)  -    { -      /* Transient error should retry */ -      if (nbytes == -2) -	return -1; +	/* If read byte is smaller than zero then error occured. */ +	if (nbytes < 0) { +		/* Transient error should retry */ +		if (nbytes == -2) +			return -1; -      zlog_err ("%s [Error] bgp_read_packet error: %s", -		peer->host, safe_strerror (errno)); +		zlog_err("%s [Error] bgp_read_packet error: %s", peer->host, +			 safe_strerror(errno)); -      if (peer->status == Established)  -	{ -	  if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) -	    { -	      peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; -	      SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); -	    } -	  else -	    peer->last_reset = PEER_DOWN_CLOSE_SESSION; -	} +		if (peer->status == Established) { +			if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { +				peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; +				SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); +			} else +				peer->last_reset = PEER_DOWN_CLOSE_SESSION; +		} -      BGP_EVENT_ADD (peer, TCP_fatal_error); -      return -1; -    }   +		BGP_EVENT_ADD(peer, TCP_fatal_error); +		return -1; +	} -  /* When read byte is zero : clear bgp peer and return */ -  if (nbytes == 0)  -    { -      if (bgp_debug_neighbor_events(peer)) -	zlog_debug ("%s [Event] BGP connection closed fd %d", -		    peer->host, peer->fd); +	/* When read byte is zero : clear bgp peer and return */ +	if (nbytes == 0) { +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s [Event] BGP connection closed fd %d", +				   peer->host, peer->fd); + +		if (peer->status == Established) { +			if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { +				peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; +				SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); +			} else +				peer->last_reset = PEER_DOWN_CLOSE_SESSION; +		} -      if (peer->status == Established)  -	{ -	  if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) -	    { -	      peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; -	      SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); -	    } -	  else -	    peer->last_reset = PEER_DOWN_CLOSE_SESSION; +		BGP_EVENT_ADD(peer, TCP_connection_closed); +		return -1;  	} -      BGP_EVENT_ADD (peer, TCP_connection_closed); -      return -1; -    } - -  /* We read partial packet. */ -  if (stream_get_endp (peer->ibuf) != peer->packet_size) -    return -1; +	/* We read partial packet. */ +	if (stream_get_endp(peer->ibuf) != peer->packet_size) +		return -1; -  return 0; +	return 0;  }  /* Marker check. */ -static int -bgp_marker_all_one (struct stream *s, int length) +static int bgp_marker_all_one(struct stream *s, int length)  { -  int i; +	int i; -  for (i = 0; i < length; i++) -    if (s->data[i] != 0xff) -      return 0; +	for (i = 0; i < length; i++) +		if (s->data[i] != 0xff) +			return 0; -  return 1; +	return 1;  }  /* Starting point of packet process function. */ -int -bgp_read (struct thread *thread) +int bgp_read(struct thread *thread)  { -  int ret; -  u_char type = 0; -  struct peer *peer; -  bgp_size_t size; -  char notify_data_length[2]; -  u_int32_t notify_out; - -  /* Yes first of all get peer pointer. */ -  peer = THREAD_ARG (thread); -  peer->t_read = NULL; - -  /* Note notify_out so we can check later to see if we sent another one */ -  notify_out = peer->notify_out; - -  /* For non-blocking IO check. */ -  if (peer->status == Connect) -    { -      bgp_connect_check (peer, 1); -      goto done; -    } -  else -    { -      if (peer->fd < 0) -	{ -	  zlog_err ("bgp_read peer's fd is negative value %d", peer->fd); -	  return -1; +	int ret; +	u_char type = 0; +	struct peer *peer; +	bgp_size_t size; +	char notify_data_length[2]; +	u_int32_t notify_out; + +	/* Yes first of all get peer pointer. */ +	peer = THREAD_ARG(thread); +	peer->t_read = NULL; + +	/* Note notify_out so we can check later to see if we sent another one +	 */ +	notify_out = peer->notify_out; + +	/* For non-blocking IO check. */ +	if (peer->status == Connect) { +		bgp_connect_check(peer, 1); +		goto done; +	} else { +		if (peer->fd < 0) { +			zlog_err("bgp_read peer's fd is negative value %d", +				 peer->fd); +			return -1; +		} +		BGP_READ_ON(peer->t_read, bgp_read, peer->fd);  	} -      BGP_READ_ON (peer->t_read, bgp_read, peer->fd); -    } - -  /* Read packet header to determine type of the packet */ -  if (peer->packet_size == 0) -    peer->packet_size = BGP_HEADER_SIZE; - -  if (stream_get_endp (peer->ibuf) < BGP_HEADER_SIZE) -    { -      ret = bgp_read_packet (peer); - -      /* Header read error or partial read packet. */ -      if (ret < 0)  -	goto done; - -      /* Get size and type. */ -      stream_forward_getp (peer->ibuf, BGP_MARKER_SIZE); -      memcpy (notify_data_length, stream_pnt (peer->ibuf), 2); -      size = stream_getw (peer->ibuf); -      type = stream_getc (peer->ibuf); - -      /* Marker check */ -      if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) -	  && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) -	{ -	  bgp_notify_send (peer, -			   BGP_NOTIFY_HEADER_ERR,  -			   BGP_NOTIFY_HEADER_NOT_SYNC); -	  goto done; + +	/* Read packet header to determine type of the packet */ +	if (peer->packet_size == 0) +		peer->packet_size = BGP_HEADER_SIZE; + +	if (stream_get_endp(peer->ibuf) < BGP_HEADER_SIZE) { +		ret = bgp_read_packet(peer); + +		/* Header read error or partial read packet. */ +		if (ret < 0) +			goto done; + +		/* Get size and type. */ +		stream_forward_getp(peer->ibuf, BGP_MARKER_SIZE); +		memcpy(notify_data_length, stream_pnt(peer->ibuf), 2); +		size = stream_getw(peer->ibuf); +		type = stream_getc(peer->ibuf); + +		/* Marker check */ +		if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) +		    && !bgp_marker_all_one(peer->ibuf, BGP_MARKER_SIZE)) { +			bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR, +					BGP_NOTIFY_HEADER_NOT_SYNC); +			goto done; +		} + +		/* BGP type check. */ +		if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE +		    && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE +		    && type != BGP_MSG_ROUTE_REFRESH_NEW +		    && type != BGP_MSG_ROUTE_REFRESH_OLD +		    && type != BGP_MSG_CAPABILITY) { +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug("%s unknown message type 0x%02x", +					   peer->host, type); +			bgp_notify_send_with_data(peer, BGP_NOTIFY_HEADER_ERR, +						  BGP_NOTIFY_HEADER_BAD_MESTYPE, +						  &type, 1); +			goto done; +		} +		/* Mimimum packet length check. */ +		if ((size < BGP_HEADER_SIZE) || (size > BGP_MAX_PACKET_SIZE) +		    || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) +		    || (type == BGP_MSG_UPDATE +			&& size < BGP_MSG_UPDATE_MIN_SIZE) +		    || (type == BGP_MSG_NOTIFY +			&& size < BGP_MSG_NOTIFY_MIN_SIZE) +		    || (type == BGP_MSG_KEEPALIVE +			&& size != BGP_MSG_KEEPALIVE_MIN_SIZE) +		    || (type == BGP_MSG_ROUTE_REFRESH_NEW +			&& size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) +		    || (type == BGP_MSG_ROUTE_REFRESH_OLD +			&& size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) +		    || (type == BGP_MSG_CAPABILITY +			&& size < BGP_MSG_CAPABILITY_MIN_SIZE)) { +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug("%s bad message length - %d for %s", +					   peer->host, size, +					   type == 128 +						   ? "ROUTE-REFRESH" +						   : bgp_type_str[(int)type]); +			bgp_notify_send_with_data(peer, BGP_NOTIFY_HEADER_ERR, +						  BGP_NOTIFY_HEADER_BAD_MESLEN, +						  (u_char *)notify_data_length, +						  2); +			goto done; +		} + +		/* Adjust size to message length. */ +		peer->packet_size = size;  	} -      /* BGP type check. */ -      if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE  -	  && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE  -	  && type != BGP_MSG_ROUTE_REFRESH_NEW -	  && type != BGP_MSG_ROUTE_REFRESH_OLD -	  && type != BGP_MSG_CAPABILITY) -	{ -          if (bgp_debug_neighbor_events(peer)) -	    zlog_debug ("%s unknown message type 0x%02x", -		        peer->host, type); -	  bgp_notify_send_with_data (peer, -				     BGP_NOTIFY_HEADER_ERR, -			 	     BGP_NOTIFY_HEADER_BAD_MESTYPE, -				     &type, 1); -	  goto done; +	ret = bgp_read_packet(peer); +	if (ret < 0) +		goto done; + +	/* Get size and type again. */ +	(void)stream_getw_from(peer->ibuf, BGP_MARKER_SIZE); +	type = stream_getc_from(peer->ibuf, BGP_MARKER_SIZE + 2); + +	/* BGP packet dump function. */ +	bgp_dump_packet(peer, type, peer->ibuf); + +	size = (peer->packet_size - BGP_HEADER_SIZE); + +	/* Read rest of the packet and call each sort of packet routine */ +	switch (type) { +	case BGP_MSG_OPEN: +		peer->open_in++; +		bgp_open_receive(peer, size); /* XXX return value ignored! */ +		break; +	case BGP_MSG_UPDATE: +		peer->readtime = monotime(NULL); +		bgp_update_receive(peer, size); +		break; +	case BGP_MSG_NOTIFY: +		bgp_notify_receive(peer, size); +		break; +	case BGP_MSG_KEEPALIVE: +		peer->readtime = monotime(NULL); +		bgp_keepalive_receive(peer, size); +		break; +	case BGP_MSG_ROUTE_REFRESH_NEW: +	case BGP_MSG_ROUTE_REFRESH_OLD: +		peer->refresh_in++; +		bgp_route_refresh_receive(peer, size); +		break; +	case BGP_MSG_CAPABILITY: +		peer->dynamic_cap_in++; +		bgp_capability_receive(peer, size); +		break;  	} -      /* Mimimum packet length check. */ -      if ((size < BGP_HEADER_SIZE) -	  || (size > BGP_MAX_PACKET_SIZE) -	  || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) -	  || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) -	  || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) -	  || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE) -	  || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) -	  || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) -	  || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) -	{ -          if (bgp_debug_neighbor_events(peer)) -	    zlog_debug ("%s bad message length - %d for %s", -		        peer->host, size, -		        type == 128 ? "ROUTE-REFRESH" : -		        bgp_type_str[(int) type]); -	  bgp_notify_send_with_data (peer, -				     BGP_NOTIFY_HEADER_ERR, -			  	     BGP_NOTIFY_HEADER_BAD_MESLEN, -				     (u_char *) notify_data_length, 2); -	  goto done; + +	/* If reading this packet caused us to send a NOTIFICATION then store a +	 * copy +	 * of the packet for troubleshooting purposes +	 */ +	if (notify_out < peer->notify_out) { +		memcpy(peer->last_reset_cause, peer->ibuf->data, +		       peer->packet_size); +		peer->last_reset_cause_size = peer->packet_size; +		notify_out = peer->notify_out; +	} + +	/* Clear input buffer. */ +	peer->packet_size = 0; +	if (peer->ibuf) +		stream_reset(peer->ibuf); + +done: +	/* If reading this packet caused us to send a NOTIFICATION then store a +	 * copy +	 * of the packet for troubleshooting purposes +	 */ +	if (notify_out < peer->notify_out) { +		memcpy(peer->last_reset_cause, peer->ibuf->data, +		       peer->packet_size); +		peer->last_reset_cause_size = peer->packet_size;  	} -      /* Adjust size to message length. */ -      peer->packet_size = size; -    } - -  ret = bgp_read_packet (peer); -  if (ret < 0)  -    goto done; - -  /* Get size and type again. */ -  (void)stream_getw_from (peer->ibuf, BGP_MARKER_SIZE); -  type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2); - -  /* BGP packet dump function. */ -  bgp_dump_packet (peer, type, peer->ibuf); -   -  size = (peer->packet_size - BGP_HEADER_SIZE); - -  /* Read rest of the packet and call each sort of packet routine */ -  switch (type)  -    { -    case BGP_MSG_OPEN: -      peer->open_in++; -      bgp_open_receive (peer, size); /* XXX return value ignored! */ -      break; -    case BGP_MSG_UPDATE: -      peer->readtime = monotime (NULL); -      bgp_update_receive (peer, size); -      break; -    case BGP_MSG_NOTIFY: -      bgp_notify_receive (peer, size); -      break; -    case BGP_MSG_KEEPALIVE: -      peer->readtime = monotime (NULL); -      bgp_keepalive_receive (peer, size); -      break; -    case BGP_MSG_ROUTE_REFRESH_NEW: -    case BGP_MSG_ROUTE_REFRESH_OLD: -      peer->refresh_in++; -      bgp_route_refresh_receive (peer, size); -      break; -    case BGP_MSG_CAPABILITY: -      peer->dynamic_cap_in++; -      bgp_capability_receive (peer, size); -      break; -    } - -  /* If reading this packet caused us to send a NOTIFICATION then store a copy -   * of the packet for troubleshooting purposes -   */ -  if (notify_out < peer->notify_out) -    { -      memcpy(peer->last_reset_cause, peer->ibuf->data, peer->packet_size); -      peer->last_reset_cause_size = peer->packet_size; -      notify_out = peer->notify_out; -    } - -  /* Clear input buffer. */ -  peer->packet_size = 0; -  if (peer->ibuf) -    stream_reset (peer->ibuf); - - done: -  /* If reading this packet caused us to send a NOTIFICATION then store a copy -   * of the packet for troubleshooting purposes -   */ -  if (notify_out < peer->notify_out) -    { -      memcpy(peer->last_reset_cause, peer->ibuf->data, peer->packet_size); -      peer->last_reset_cause_size = peer->packet_size; -    } - -  return 0; +	return 0;  }  | 
