bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
{
  afi_t afi;
  safi_t safi;
  u_char reserved;
  struct stream *s;

  /* If peer does not have the capability, send notification. */
  if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV))
    {
      plog_err (peer->log, "%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) 
    {
      plog_err (peer->log,
		"%s [Error] Route refresh packet received under status %s",
		peer->host, LOOKUP (bgp_status_msg, peer->status));
      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
      return;
    }

  s = peer->ibuf;
  
  /* Parse packet. */
  afi = stream_getw (s);
  reserved = stream_getc (s);
  safi = stream_getc (s);

  if (BGP_DEBUG (normal, NORMAL))
    zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d",
	       peer->host, afi, safi);

  /* Check AFI and SAFI. */
  if ((afi != AFI_IP && afi != AFI_IP6)
      || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
	  && safi != SAFI_MPLS_LABELED_VPN))
    {
      if (BGP_DEBUG (normal, NORMAL))
	{
	  zlog_debug ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored",
		     peer->host, afi, safi);
	}
      return;
    }

  /* Adjust safi code. */
  if (safi == SAFI_MPLS_LABELED_VPN)
    safi = SAFI_MPLS_VPN;

  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)
	    {
	      u_char *p_pnt = stream_pnt (s);
	      u_char *p_end = stream_pnt (s) + orf_len;
	      struct orf_prefix orfp;
	      u_char common = 0;
	      u_int32_t seq;
	      int psize;
	      char name[BUFSIZ];
	      char buf[BUFSIZ];
	      int ret;

	      if (BGP_DEBUG (normal, NORMAL))
		{
		  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 (normal, NORMAL))
			zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host);
		      prefix_bgp_orf_remove_all (name);
		      break;
		    }
		  ok = ((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 (normal, NORMAL))
		    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, 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 || (ret != CMD_SUCCESS))
		    {
		      if (BGP_DEBUG (normal, NORMAL))
			zlog_debug ("%s Received misformatted prefixlist ORF."
			            " Remove All pfxlist", peer->host);
		      prefix_bgp_orf_remove_all (name);
		      break;
		    }
		}
	      peer->orf_plist[afi][safi] =
			 prefix_list_lookup (AFI_ORF_PREFIX, name);
	    }
	  stream_forward_getp (s, orf_len);
	}
      if (BGP_DEBUG (normal, NORMAL))
	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);

  /* Perform route refreshment to the peer */
  bgp_announce_route (peer, afi, safi);
}