Diff for /embedaddon/quagga/bgpd/bgp_attr.c between versions 1.1.1.1 and 1.1.1.4

version 1.1.1.1, 2012/02/21 17:26:12 version 1.1.1.4, 2016/11/02 10:09:10
Line 29  Software Foundation, Inc., 59 Temple Place - Suite 330 Line 29  Software Foundation, Inc., 59 Temple Place - Suite 330
 #include "log.h"  #include "log.h"
 #include "hash.h"  #include "hash.h"
 #include "jhash.h"  #include "jhash.h"
   #include "filter.h"
   
 #include "bgpd/bgpd.h"  #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"  #include "bgpd/bgp_attr.h"
Line 38  Software Foundation, Inc., 59 Temple Place - Suite 330 Line 39  Software Foundation, Inc., 59 Temple Place - Suite 330
 #include "bgpd/bgp_debug.h"  #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_packet.h"  #include "bgpd/bgp_packet.h"
 #include "bgpd/bgp_ecommunity.h"  #include "bgpd/bgp_ecommunity.h"
#include "table.h"
 #include "bgp_encap_types.h"
 
 /* Attribute strings for logging. */  /* Attribute strings for logging. */
 static const struct message attr_str [] =   static const struct message attr_str [] = 
 {  {
Line 51  static const struct message attr_str [] =  Line 54  static const struct message attr_str [] = 
   { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" },     { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" }, 
   { BGP_ATTR_COMMUNITIES,      "COMMUNITY" },     { BGP_ATTR_COMMUNITIES,      "COMMUNITY" }, 
   { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },    { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },
  { BGP_ATTR_CLUSTER_LIST,     "CLUSTERLIST" },   { BGP_ATTR_CLUSTER_LIST,     "CLUSTER_LIST" }, 
   { BGP_ATTR_DPA,              "DPA" },    { BGP_ATTR_DPA,              "DPA" },
   { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,    { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,
   { BGP_ATTR_RCID_PATH,        "RCID_PATH" },    { BGP_ATTR_RCID_PATH,        "RCID_PATH" },
Line 61  static const struct message attr_str [] =  Line 64  static const struct message attr_str [] = 
   { BGP_ATTR_AS4_PATH,         "AS4_PATH" },     { BGP_ATTR_AS4_PATH,         "AS4_PATH" }, 
   { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" },     { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" }, 
   { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },    { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },
     { BGP_ATTR_ENCAP,            "ENCAP" },
 };  };
static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);static const int attr_str_max = array_size(attr_str);
 static const struct message attr_flag_str[] =
 {
   { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
   { BGP_ATTR_FLAG_TRANS,    "Transitive" },
   { BGP_ATTR_FLAG_PARTIAL,  "Partial" },
   /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
   { BGP_ATTR_FLAG_EXTLEN,   "Extended Length" },
 };
 
 static struct hash *cluster_hash;  static struct hash *cluster_hash;
   
 static void *  static void *
Line 175  cluster_intern (struct cluster_list *cluster) Line 188  cluster_intern (struct cluster_list *cluster)
 void  void
 cluster_unintern (struct cluster_list *cluster)  cluster_unintern (struct cluster_list *cluster)
 {  {
   struct cluster_list *ret;  
   
   if (cluster->refcnt)    if (cluster->refcnt)
     cluster->refcnt--;      cluster->refcnt--;
   
   if (cluster->refcnt == 0)    if (cluster->refcnt == 0)
     {      {
      ret = hash_release (cluster_hash, cluster);      hash_release (cluster_hash, cluster);
       cluster_free (cluster);        cluster_free (cluster);
     }      }
 }  }
Line 196  cluster_init (void) Line 207  cluster_init (void)
 static void  static void
 cluster_finish (void)  cluster_finish (void)
 {  {
     hash_clean (cluster_hash, (void (*)(void *))cluster_free);
   hash_free (cluster_hash);    hash_free (cluster_hash);
   cluster_hash = NULL;    cluster_hash = NULL;
 }  }
 struct bgp_attr_encap_subtlv *
 encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
 {
     struct bgp_attr_encap_subtlv *new;
     struct bgp_attr_encap_subtlv *tail;
     struct bgp_attr_encap_subtlv *p;
 
     for (p = orig, tail = new = NULL; p; p = p->next) {
         int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length;
         if (tail) {
             tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
             tail = tail->next;
         } else {
             tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
         }
         assert(tail);
         memcpy(tail, p, size);
         tail->next = NULL;
     }
 
     return new;
 }
 
 static void
 encap_free(struct bgp_attr_encap_subtlv *p)
 {
     struct bgp_attr_encap_subtlv *next;
     while (p) {
         next    = p->next;
         p->next = NULL;
         XFREE(MTYPE_ENCAP_TLV, p);
         p       = next;
     }
 }
 
 void
 bgp_attr_flush_encap(struct attr *attr)
 {
     if (!attr || !attr->extra)
         return;
 
     if (attr->extra->encap_subtlvs) {
         encap_free(attr->extra->encap_subtlvs);
         attr->extra->encap_subtlvs = NULL;
     }
 }
 
 /*
  * Compare encap sub-tlv chains
  *
  *      1 = equivalent
  *      0 = not equivalent
  *
  * This algorithm could be made faster if needed
  */
 static int
 encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2)
 {
     struct bgp_attr_encap_subtlv *p;
     struct bgp_attr_encap_subtlv *q;
 
     if (!h1 && !h2)
         return 1;
     if (h1 && !h2)
         return 0;
     if (!h1 && h2)
         return 0;
     if (h1 == h2)
         return 1;
 
     for (p = h1; p; p = p->next) {
         for (q = h2; q; q = q->next) {
             if ((p->type == q->type) &&
                 (p->length == q->length) &&
                 !memcmp(p->value, q->value, p->length)) {
 
                 break;
             }
         }
         if (!q)
             return 0;
     }
 
     for (p = h2; p; p = p->next) {
         for (q = h1; q; q = q->next) {
             if ((p->type == q->type) &&
                 (p->length == q->length) &&
                 !memcmp(p->value, q->value, p->length)) {
 
                 break;
             }
         }
         if (!q)
             return 0;
     }
 
     return 1;
 }
 
 /* Unknown transit attribute. */  /* Unknown transit attribute. */
 static struct hash *transit_hash;  static struct hash *transit_hash;
   
Line 235  transit_intern (struct transit *transit) Line 346  transit_intern (struct transit *transit)
 void  void
 transit_unintern (struct transit *transit)  transit_unintern (struct transit *transit)
 {  {
   struct transit *ret;  
   
   if (transit->refcnt)    if (transit->refcnt)
     transit->refcnt--;      transit->refcnt--;
   
   if (transit->refcnt == 0)    if (transit->refcnt == 0)
     {      {
      ret = hash_release (transit_hash, transit);      hash_release (transit_hash, transit);
       transit_free (transit);        transit_free (transit);
     }      }
 }  }
Line 274  transit_init (void) Line 383  transit_init (void)
 static void  static void
 transit_finish (void)  transit_finish (void)
 {  {
     hash_clean (transit_hash, (void (*)(void *))transit_free);
   hash_free (transit_hash);    hash_free (transit_hash);
   transit_hash = NULL;    transit_hash = NULL;
 }  }
 /* Attribute hash routines. */  /* Attribute hash routines. */
 static struct hash *attrhash;  static struct hash *attrhash;
   
Line 292  bgp_attr_extra_free (struct attr *attr) Line 402  bgp_attr_extra_free (struct attr *attr)
 {  {
   if (attr->extra)    if (attr->extra)
     {      {
         if (attr->extra->encap_subtlvs) {
           encap_free(attr->extra->encap_subtlvs);
           attr->extra->encap_subtlvs = NULL;
         }
       XFREE (MTYPE_ATTR_EXTRA, attr->extra);        XFREE (MTYPE_ATTR_EXTRA, attr->extra);
       attr->extra = NULL;        attr->extra = NULL;
     }      }
Line 312  bgp_attr_extra_get (struct attr *attr) Line 426  bgp_attr_extra_get (struct attr *attr)
 void  void
 bgp_attr_dup (struct attr *new, struct attr *orig)  bgp_attr_dup (struct attr *new, struct attr *orig)
 {  {
     struct attr_extra *extra = new->extra;
   
   *new = *orig;    *new = *orig;
  if (orig->extra)  /* if caller provided attr_extra space, use it in any case.
    *
    * This is neccesary even if orig->extra equals NULL, because otherwise
    * memory may be later allocated on the heap by bgp_attr_extra_get.
    *
    * That memory would eventually be leaked, because the caller must not
    * call bgp_attr_extra_free if he provided attr_extra on the stack.
    */
   if (extra)
     {      {
         new->extra = extra;
         memset(new->extra, 0, sizeof(struct attr_extra));
         if (orig->extra) {
           *new->extra = *orig->extra;
           if (orig->extra->encap_subtlvs) {
             new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
           }
         }
       }
     else if (orig->extra)
       {
       new->extra = bgp_attr_extra_new();        new->extra = bgp_attr_extra_new();
       *new->extra = *orig->extra;        *new->extra = *orig->extra;
         if (orig->extra->encap_subtlvs) {
           new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
         }
     }      }
 }  }
   
Line 335  attr_unknown_count (void) Line 473  attr_unknown_count (void)
 unsigned int  unsigned int
 attrhash_key_make (void *p)  attrhash_key_make (void *p)
 {  {
  const struct attr * attr = (struct attr *) p;  const struct attr *attr = (struct attr *) p;
   const struct attr_extra *extra = attr->extra;
   uint32_t key = 0;    uint32_t key = 0;
 #define MIX(val)        key = jhash_1word(val, key)  #define MIX(val)        key = jhash_1word(val, key)
   
Line 349  attrhash_key_make (void *p) Line 488  attrhash_key_make (void *p)
   key += attr->med;    key += attr->med;
   key += attr->local_pref;    key += attr->local_pref;
       
  if (attr->extra)  if (extra)
     {      {
      MIX(attr->extra->aggregator_as);      MIX(extra->aggregator_as);
      MIX(attr->extra->aggregator_addr.s_addr);      MIX(extra->aggregator_addr.s_addr);
      MIX(attr->extra->weight);      MIX(extra->weight);
      MIX(attr->extra->mp_nexthop_global_in.s_addr);      MIX(extra->mp_nexthop_global_in.s_addr);
       MIX(extra->originator_id.s_addr);
     }      }
       
   if (attr->aspath)    if (attr->aspath)
Line 362  attrhash_key_make (void *p) Line 502  attrhash_key_make (void *p)
   if (attr->community)    if (attr->community)
     MIX(community_hash_make (attr->community));      MIX(community_hash_make (attr->community));
       
  if (attr->extra)  if (extra)
     {      {
      if (attr->extra->ecommunity)      if (extra->ecommunity)
        MIX(ecommunity_hash_make (attr->extra->ecommunity));        MIX(ecommunity_hash_make (extra->ecommunity));
      if (attr->extra->cluster)      if (extra->cluster)
        MIX(cluster_hash_key_make (attr->extra->cluster));        MIX(cluster_hash_key_make (extra->cluster));
      if (attr->extra->transit)      if (extra->transit)
        MIX(transit_hash_key_make (attr->extra->transit));        MIX(transit_hash_key_make (extra->transit));
   
#ifdef HAVE_IPV6      MIX(extra->mp_nexthop_len);
      MIX(attr->extra->mp_nexthop_len);      key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
      key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);      key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
      key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key); 
#endif /* HAVE_IPV6 */ 
     }      }
   
   return key;    return key;
Line 402  attrhash_cmp (const void *p1, const void *p2) Line 540  attrhash_cmp (const void *p1, const void *p2)
           && ae1->aggregator_as == ae2->aggregator_as            && ae1->aggregator_as == ae2->aggregator_as
           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr            && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
           && ae1->weight == ae2->weight            && ae1->weight == ae2->weight
 #ifdef HAVE_IPV6  
           && ae1->mp_nexthop_len == ae2->mp_nexthop_len            && ae1->mp_nexthop_len == ae2->mp_nexthop_len
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)            && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)            && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
 #endif /* HAVE_IPV6 */  
           && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)            && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
           && ae1->ecommunity == ae2->ecommunity            && ae1->ecommunity == ae2->ecommunity
           && ae1->cluster == ae2->cluster            && ae1->cluster == ae2->cluster
          && ae1->transit == ae2->transit)          && ae1->transit == ae2->transit
           && (ae1->encap_tunneltype == ae2->encap_tunneltype)
           && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs)
           && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
         return 1;          return 1;
       else if (ae1 || ae2)        else if (ae1 || ae2)
         return 0;          return 0;
Line 427  attrhash_init (void) Line 566  attrhash_init (void)
   attrhash = hash_create (attrhash_key_make, attrhash_cmp);    attrhash = hash_create (attrhash_key_make, attrhash_cmp);
 }  }
   
   /*
    * special for hash_clean below
    */
 static void  static void
   attr_vfree (void *attr)
   {
     bgp_attr_extra_free ((struct attr *)attr);
     XFREE (MTYPE_ATTR, attr);
   }
   
   static void
 attrhash_finish (void)  attrhash_finish (void)
 {  {
     hash_clean(attrhash, attr_vfree);
   hash_free (attrhash);    hash_free (attrhash);
   attrhash = NULL;    attrhash = NULL;
 }  }
Line 464  bgp_attr_hash_alloc (void *p) Line 614  bgp_attr_hash_alloc (void *p)
     {      {
       attr->extra = bgp_attr_extra_new ();        attr->extra = bgp_attr_extra_new ();
       *attr->extra = *val->extra;        *attr->extra = *val->extra;
   
         if (attr->extra->encap_subtlvs) {
           attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs);
         }
     }      }
   attr->refcnt = 0;    attr->refcnt = 0;
   return attr;    return attr;
Line 538  bgp_attr_default_set (struct attr *attr, u_char origin Line 692  bgp_attr_default_set (struct attr *attr, u_char origin
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
   attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;    attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 #ifdef HAVE_IPV6  
   attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;    attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
 #endif  
   
   return attr;    return attr;
 }  }
Line 552  bgp_attr_default_intern (u_char origin) Line 704  bgp_attr_default_intern (u_char origin)
 {  {
   struct attr attr;    struct attr attr;
   struct attr *new;    struct attr *new;
  struct attr_extra *attre;
   
   memset (&attr, 0, sizeof (struct attr));    memset (&attr, 0, sizeof (struct attr));
  attre = bgp_attr_extra_get (&attr);  bgp_attr_extra_get (&attr);
  
   bgp_attr_default_set(&attr, origin);    bgp_attr_default_set(&attr, origin);
   
   new = bgp_attr_intern (&attr);    new = bgp_attr_intern (&attr);
Line 573  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori Line 724  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
 {  {
   struct attr attr;    struct attr attr;
   struct attr *new;    struct attr *new;
  struct attr_extra *attre;  struct attr_extra attre;
   
   memset (&attr, 0, sizeof (struct attr));    memset (&attr, 0, sizeof (struct attr));
  attre = bgp_attr_extra_get (&attr);  memset (&attre, 0, sizeof (struct attr_extra));
    attr.extra = &attre;
 
   /* Origin attribute. */    /* Origin attribute. */
   attr.origin = origin;    attr.origin = origin;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
Line 598  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori Line 750  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
       attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);        attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
     }      }
   
  attre->weight = BGP_ATTR_DEFAULT_WEIGHT;  attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
#ifdef HAVE_IPV6  attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
  attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
#endif 
   if (! as_set)    if (! as_set)
     attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
   if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))    if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
    attre->aggregator_as = bgp->confed_id;    attre.aggregator_as = bgp->confed_id;
   else    else
    attre->aggregator_as = bgp->as;    attre.aggregator_as = bgp->as;
  attre->aggregator_addr = bgp->router_id;  attre.aggregator_addr = bgp->router_id;
   
   new = bgp_attr_intern (&attr);    new = bgp_attr_intern (&attr);
  bgp_attr_extra_free (&attr);
   
   aspath_unintern (&new->aspath);    aspath_unintern (&new->aspath);
   return new;    return new;
 }  }
Line 625  bgp_attr_unintern_sub (struct attr *attr) Line 775  bgp_attr_unintern_sub (struct attr *attr)
   /* aspath refcount shoud be decrement. */    /* aspath refcount shoud be decrement. */
   if (attr->aspath)    if (attr->aspath)
     aspath_unintern (&attr->aspath);      aspath_unintern (&attr->aspath);
  UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);  UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH));
       
   if (attr->community)    if (attr->community)
     community_unintern (&attr->community);      community_unintern (&attr->community);
  UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);  UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
       
   if (attr->extra)    if (attr->extra)
     {      {
       if (attr->extra->ecommunity)        if (attr->extra->ecommunity)
         ecommunity_unintern (&attr->extra->ecommunity);          ecommunity_unintern (&attr->extra->ecommunity);
      UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);      UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
               
       if (attr->extra->cluster)        if (attr->extra->cluster)
         cluster_unintern (attr->extra->cluster);          cluster_unintern (attr->extra->cluster);
      UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);      UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
               
       if (attr->extra->transit)        if (attr->extra->transit)
         transit_unintern (attr->extra->transit);          transit_unintern (attr->extra->transit);
Line 648  bgp_attr_unintern_sub (struct attr *attr) Line 798  bgp_attr_unintern_sub (struct attr *attr)
   
 /* Free bgp attribute and aspath. */  /* Free bgp attribute and aspath. */
 void  void
bgp_attr_unintern (struct attr **attr)bgp_attr_unintern (struct attr **pattr)
 {  {
     struct attr *attr = *pattr;
   struct attr *ret;    struct attr *ret;
   struct attr tmp;    struct attr tmp;
     struct attr_extra tmp_extra;
       
   /* Decrement attribute reference. */    /* Decrement attribute reference. */
  (*attr)->refcnt--;  attr->refcnt--;
       
  tmp = *(*attr);  tmp = *attr;
       
  if ((*attr)->extra)  if (attr->extra)
     {      {
      tmp.extra = bgp_attr_extra_new ();      tmp.extra = &tmp_extra;
      memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));      memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
     }      }
       
   /* If reference becomes zero then free attribute object. */    /* If reference becomes zero then free attribute object. */
  if ((*attr)->refcnt == 0)  if (attr->refcnt == 0)
    {        {
      ret = hash_release (attrhash, *attr);      ret = hash_release (attrhash, attr);
       assert (ret != NULL);        assert (ret != NULL);
      bgp_attr_extra_free (*attr);      bgp_attr_extra_free (attr);
      XFREE (MTYPE_ATTR, *attr);      XFREE (MTYPE_ATTR, attr);
      *attr = NULL;      *pattr = NULL;
     }      }
   
   bgp_attr_unintern_sub (&tmp);    bgp_attr_unintern_sub (&tmp);
Line 681  void Line 833  void
 bgp_attr_flush (struct attr *attr)  bgp_attr_flush (struct attr *attr)
 {  {
   if (attr->aspath && ! attr->aspath->refcnt)    if (attr->aspath && ! attr->aspath->refcnt)
    aspath_free (attr->aspath);    {
       aspath_free (attr->aspath);
       attr->aspath = NULL;
     }
   if (attr->community && ! attr->community->refcnt)    if (attr->community && ! attr->community->refcnt)
    community_free (attr->community);    {
       community_free (attr->community);
       attr->community = NULL;
     }
   if (attr->extra)    if (attr->extra)
     {      {
       struct attr_extra *attre = attr->extra;        struct attr_extra *attre = attr->extra;
Line 691  bgp_attr_flush (struct attr *attr) Line 849  bgp_attr_flush (struct attr *attr)
       if (attre->ecommunity && ! attre->ecommunity->refcnt)        if (attre->ecommunity && ! attre->ecommunity->refcnt)
         ecommunity_free (&attre->ecommunity);          ecommunity_free (&attre->ecommunity);
       if (attre->cluster && ! attre->cluster->refcnt)        if (attre->cluster && ! attre->cluster->refcnt)
        cluster_free (attre->cluster);        {
           cluster_free (attre->cluster);
           attre->cluster = NULL;
         }
       if (attre->transit && ! attre->transit->refcnt)        if (attre->transit && ! attre->transit->refcnt)
        transit_free (attre->transit);        {
           transit_free (attre->transit);
           attre->transit = NULL;
         }
       encap_free(attre->encap_subtlvs);
       attre->encap_subtlvs = NULL;
     }      }
 }  }
   
Line 703  bgp_attr_flush (struct attr *attr) Line 869  bgp_attr_flush (struct attr *attr)
  * introduced by the sending neighbour.   * introduced by the sending neighbour.
  */   */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
                    u_char subcode, u_char *startp, bgp_size_t length)                    bgp_size_t length)
 {  {
     struct peer *const peer = args->peer; 
     const u_int8_t flags = args->flags;
     /* startp and length must be special-cased, as whether or not to
      * send the attribute data with the NOTIFY depends on the error,
      * the caller therefore signals this with the seperate length argument
      */
     u_char *notify_datap = (length > 0 ? args->startp : NULL);
     
   /* Only relax error handling for eBGP peers */    /* Only relax error handling for eBGP peers */
  if (peer_sort (peer) != BGP_PEER_EBGP)  if (peer->sort != BGP_PEER_EBGP)
     {      {
       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,        bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
                                 startp, length);                                 notify_datap, length);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
   
     }      }
       
  switch (type) {  /* Adjust the stream getp to the end of the attribute, in case we can
    /* where an optional attribute is inconsequential, e.g. it does not affect   * still proceed but the caller hasn't read all the attribute.
     * route selection, and can be safely ignored then any such attributes   */
     * which are malformed should just be ignored and the route processed as  stream_set_getp (BGP_INPUT (peer),
     * normal.                   (args->startp - STREAM_DATA (BGP_INPUT (peer)))
                     + args->total);
   
   switch (args->type) {
     /* where an attribute is relatively inconsequential, e.g. it does not
      * affect route selection, and can be safely ignored, then any such
      * attributes which are malformed should just be ignored and the route
      * processed as normal.
      */       */
     case BGP_ATTR_AS4_AGGREGATOR:      case BGP_ATTR_AS4_AGGREGATOR:
     case BGP_ATTR_AGGREGATOR:      case BGP_ATTR_AGGREGATOR:
Line 727  bgp_attr_malformed (struct peer *peer, u_char type, u_ Line 908  bgp_attr_malformed (struct peer *peer, u_char type, u_
       return BGP_ATTR_PARSE_PROCEED;        return BGP_ATTR_PARSE_PROCEED;
           
     /* Core attributes, particularly ones which may influence route      /* Core attributes, particularly ones which may influence route
     * selection should always cause session resets     * selection, should always cause session resets
      */       */
     case BGP_ATTR_ORIGIN:      case BGP_ATTR_ORIGIN:
     case BGP_ATTR_AS_PATH:      case BGP_ATTR_AS_PATH:
Line 741  bgp_attr_malformed (struct peer *peer, u_char type, u_ Line 922  bgp_attr_malformed (struct peer *peer, u_char type, u_
     case BGP_ATTR_MP_UNREACH_NLRI:      case BGP_ATTR_MP_UNREACH_NLRI:
     case BGP_ATTR_EXT_COMMUNITIES:      case BGP_ATTR_EXT_COMMUNITIES:
       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,        bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
                                 startp, length);                                 notify_datap, length);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
   }    }
       
Line 749  bgp_attr_malformed (struct peer *peer, u_char type, u_ Line 930  bgp_attr_malformed (struct peer *peer, u_char type, u_
    * the whole session to be reset. Instead treat it as a withdrawal     * the whole session to be reset. Instead treat it as a withdrawal
    * of the routes, if possible.     * of the routes, if possible.
    */     */
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)  if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
      && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)      && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
      && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))      && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
     return BGP_ATTR_PARSE_WITHDRAW;      return BGP_ATTR_PARSE_WITHDRAW;
       
   /* default to reset */    /* default to reset */
  return BGP_ATTR_PARSE_ERROR;  return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
 }  }
   
/* Get origin attribute of the update message. *//* Find out what is wrong with the path attribute flag bits and log the error.
static bgp_attr_parse_ret_t   "Flag bits" here stand for Optional, Transitive and Partial, but not for
bgp_attr_origin (struct peer *peer, bgp_size_t length,    Extended Length. Checking O/T/P bits at once implies, that the attribute
                 struct attr *attr, u_char flag, u_char *startp)   being diagnosed is defined by RFC as either a "well-known" or an "optional,
    non-transitive" attribute. */
 static void
 bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
                          u_int8_t desired_flags /* how RFC says it must be */
 )
 {  {
  bgp_size_t total;  u_char seen = 0, i;
   u_char real_flags = args->flags;
   const u_int8_t attr_code = args->type;
   
   desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
   real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
   for (i = 0; i <= 2; i++) /* O,T,P, but not E */
     if
     (
       CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
       CHECK_FLAG (real_flags,    attr_flag_str[i].key)
     )
     {
       zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
             LOOKUP (attr_str, attr_code),
             CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
             attr_flag_str[i].str);
       seen = 1;
     }
   if (!seen)
     {
       zlog (args->peer->log, LOG_DEBUG,
             "Strange, %s called for attr %s, but no problem found with flags"
             " (real flags 0x%x, desired 0x%x)",
             __func__, LOOKUP (attr_str, attr_code),
             real_flags, desired_flags);
     }
 }
   
  /* total is entire attribute length include Attribute Flags (1),/* Required flags for attributes. EXTLEN will be masked off when testing,
     Attribute Type code (1) and Attribute length (1 or 2).  */ * as will PARTIAL for optional+transitive attributes.
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); */
 const u_int8_t attr_flags_values [] = {
   [BGP_ATTR_ORIGIN] =           BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS_PATH] =          BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_NEXT_HOP] =         BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_MULTI_EXIT_DISC] =  BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_LOCAL_PREF] =       BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AGGREGATOR] =       BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_COMMUNITIES] =      BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_ORIGINATOR_ID] =    BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_CLUSTER_LIST] =     BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_MP_REACH_NLRI] =    BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_MP_UNREACH_NLRI] =  BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_EXT_COMMUNITIES] =  BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
 };
 static const size_t attr_flags_values_max =
   sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
   
  /* If any recognized attribute has Attribute Flags that conflictstatic int
     with the Attribute Type Code, then the Error Subcode is set tobgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
     Attribute Flags Error.  The Data field contains the erroneous{
     attribute (type, length and value). */  u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
  if (flag != BGP_ATTR_FLAG_TRANS)  const u_int8_t flags = args->flags;
   const u_int8_t attr_code = args->type;
   struct peer *const peer = args->peer; 
   
   /* there may be attributes we don't know about */
   if (attr_code > attr_flags_values_max)
     return 0;
   if (attr_flags_values[attr_code] == 0)
     return 0;
   
   /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
    * 1."
    */
   if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
       && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
     {      {
      zlog (peer->log, LOG_ERR,       zlog (peer->log, LOG_ERR,
            "Origin attribute flag isn't transitive %d", flag);            "%s well-known attributes must have transitive flag set (%x)",
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,            LOOKUP (attr_str, attr_code), flags);
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,      return 1;
                                 startp, total); 
     }      }
     
     /* "For well-known attributes and for optional non-transitive attributes,
      *  the Partial bit MUST be set to 0." 
      */
     if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
       {
         if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
           {
             zlog (peer->log, LOG_ERR,
                   "%s well-known attribute "
                   "must NOT have the partial flag set (%x)",
                    LOOKUP (attr_str, attr_code), flags);
             return 1;
           }
         if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
             && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
           {
             zlog (peer->log, LOG_ERR,
                   "%s optional + transitive attribute "
                   "must NOT have the partial flag set (%x)",
                    LOOKUP (attr_str, attr_code), flags);
             return 1;
           }
       }
     
     /* Optional transitive attributes may go through speakers that don't
      * reocgnise them and set the Partial bit.
      */
     if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
         && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
       SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
     
     if ((flags & ~mask)
         == attr_flags_values[attr_code])
       return 0;
     
     bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
     return 1;
   }
   
   /* Get origin attribute of the update message. */
   static bgp_attr_parse_ret_t
   bgp_attr_origin (struct bgp_attr_parser_args *args)
   {
     struct peer *const peer = args->peer;
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
   /* If any recognized attribute has Attribute Length that conflicts    /* If any recognized attribute has Attribute Length that conflicts
      with the expected length (based on the attribute type code), then       with the expected length (based on the attribute type code), then
      the Error Subcode is set to Attribute Length Error.  The Data       the Error Subcode is set to Attribute Length Error.  The Data
Line 791  bgp_attr_origin (struct peer *peer, bgp_size_t length, Line 1083  bgp_attr_origin (struct peer *peer, bgp_size_t length,
     {      {
       zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",        zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
             length);              length);
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 startp, total);                                 args->total);
     }      }
   
   /* Fetch origin attribute. */    /* Fetch origin attribute. */
Line 808  bgp_attr_origin (struct peer *peer, bgp_size_t length, Line 1100  bgp_attr_origin (struct peer *peer, bgp_size_t length,
     {      {
       zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",        zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
               attr->origin);                attr->origin);
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_INVAL_ORIGIN,                                   BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
                                 startp, total);                                 args->total);
     }      }
   
   /* Set oring attribute flag. */    /* Set oring attribute flag. */
Line 822  bgp_attr_origin (struct peer *peer, bgp_size_t length, Line 1114  bgp_attr_origin (struct peer *peer, bgp_size_t length,
 /* Parse AS path information.  This function is wrapper of  /* Parse AS path information.  This function is wrapper of
    aspath_parse. */     aspath_parse. */
 static int  static int
bgp_attr_aspath (struct peer *peer, bgp_size_t length, bgp_attr_aspath (struct bgp_attr_parser_args *args)
                 struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct attr *const attr = args->attr;
  struct peer *const peer = args->peer; 
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  
  /* Flag check. */ 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) 
      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR,  
            "As-Path attribute flag isn't transitive %d", flag); 
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
    } 
 
   /*    /*
    * peer with AS4 => will get 4Byte ASnums     * peer with AS4 => will get 4Byte ASnums
    * otherwise, will get 16 Bit     * otherwise, will get 16 Bit
Line 853  bgp_attr_aspath (struct peer *peer, bgp_size_t length, Line 1133  bgp_attr_aspath (struct peer *peer, bgp_size_t length,
       zlog (peer->log, LOG_ERR,        zlog (peer->log, LOG_ERR,
             "Malformed AS path from %s, length is %d",              "Malformed AS path from %s, length is %d",
             peer->host, length);              peer->host, length);
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,      return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH, 
                                 NULL, 0); 
     }      }
   
   /* Set aspath attribute flag. */    /* Set aspath attribute flag. */
Line 865  bgp_attr_aspath (struct peer *peer, bgp_size_t length, Line 1143  bgp_attr_aspath (struct peer *peer, bgp_size_t length,
 }  }
   
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
 {  {
   /* These checks were part of bgp_attr_aspath, but with    /* These checks were part of bgp_attr_aspath, but with
    * as4 we should to check aspath things when     * as4 we should to check aspath things when
Line 877  bgp_attr_aspath_check (struct peer *peer, struct attr  Line 1155  bgp_attr_aspath_check (struct peer *peer, struct attr 
   struct bgp *bgp = peer->bgp;    struct bgp *bgp = peer->bgp;
   struct aspath *aspath;    struct aspath *aspath;
   
   bgp = peer->bgp;  
       
   /* Confederation sanity check. */    /* Confederation sanity check. */
  if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||  if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
     (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))     (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
     {      {
       zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);        zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH,                       BGP_NOTIFY_UPDATE_MAL_AS_PATH);
                                 NULL, 0);      return BGP_ATTR_PARSE_ERROR;
     }      }
   
   /* First AS check for EBGP. */    /* First AS check for EBGP. */
   if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))    if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
     {      {
      if (peer_sort (peer) == BGP_PEER_EBGP       if (peer->sort == BGP_PEER_EBGP
           && ! aspath_firstas_check (attr->aspath, peer->as))            && ! aspath_firstas_check (attr->aspath, peer->as))
         {          {
           zlog (peer->log, LOG_ERR,            zlog (peer->log, LOG_ERR,
                 "%s incorrect first AS (must be %u)", peer->host, peer->as);                  "%s incorrect first AS (must be %u)", peer->host, peer->as);
          return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,          bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
                                     BGP_NOTIFY_UPDATE_MAL_AS_PATH,                           BGP_NOTIFY_UPDATE_MAL_AS_PATH);
                                     NULL, 0);          return BGP_ATTR_PARSE_ERROR;
         }          }
     }      }
   
Line 919  bgp_attr_aspath_check (struct peer *peer, struct attr  Line 1195  bgp_attr_aspath_check (struct peer *peer, struct attr 
 /* Parse AS4 path information.  This function is another wrapper of  /* Parse AS4 path information.  This function is another wrapper of
    aspath_parse. */     aspath_parse. */
 static int  static int
bgp_attr_as4_path (struct peer *peer, bgp_size_t length,bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
                 struct attr *attr, u_char flag, u_char *startp, 
                 struct aspath **as4_path) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
  struct attr *const attr = args->attr;
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  
  /* Flag check. */ 
  if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) 
      || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR,  
            "As4-Path attribute flag isn't optional/transitive %d", flag); 
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
    } 
 
   *as4_path = aspath_parse (peer->ibuf, length, 1);    *as4_path = aspath_parse (peer->ibuf, length, 1);
   
   /* In case of IBGP, length will be zero. */    /* In case of IBGP, length will be zero. */
Line 946  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt Line 1209  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
       zlog (peer->log, LOG_ERR,        zlog (peer->log, LOG_ERR,
             "Malformed AS4 path from %s, length is %d",              "Malformed AS4 path from %s, length is %d",
             peer->host, length);              peer->host, length);
      return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_MAL_AS_PATH,                                   BGP_NOTIFY_UPDATE_MAL_AS_PATH,
                                 NULL, 0);                                 0);
     }      }
   
   /* Set aspath attribute flag. */    /* Set aspath attribute flag. */
Line 960  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt Line 1223  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
   
 /* Nexthop attribute. */  /* Nexthop attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_nexthop (struct peer *peer, bgp_size_t length, bgp_attr_nexthop (struct bgp_attr_parser_args *args)
                  struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
   struct attr *const attr = args->attr;
   const bgp_size_t length = args->length;
   
   in_addr_t nexthop_h, nexthop_n;
   
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  
   
   /* Flag check. */  
   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)  
       || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))  
     {  
       zlog (peer->log, LOG_ERR,   
             "Origin attribute flag isn't transitive %d", flag);  
       return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,  
                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,  
                                  startp, total);  
     }  
   
   /* Check nexthop attribute length. */    /* Check nexthop attribute length. */
   if (length != 4)    if (length != 4)
     {      {
       zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",        zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
               length);                length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 startp, total);                                 args->total);
     }      }
   
  attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);  /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
      attribute must result in a NOTIFICATION message (this is implemented below).
      At the same time, semantically incorrect NEXT_HOP is more likely to be just
      logged locally (this is implemented somewhere else). The UPDATE message
      gets ignored in any of these cases. */
   nexthop_n = stream_get_ipv4 (peer->ibuf);
   nexthop_h = ntohl (nexthop_n);
   if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
     {
       char buf[INET_ADDRSTRLEN];
       inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
       zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
       return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
                                  args->total);
     }
 
   attr->nexthop.s_addr = nexthop_n;
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
Line 997  bgp_attr_nexthop (struct peer *peer, bgp_size_t length Line 1267  bgp_attr_nexthop (struct peer *peer, bgp_size_t length
   
 /* MED atrribute. */  /* MED atrribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_med (struct peer *peer, bgp_size_t length, bgp_attr_med (struct bgp_attr_parser_args *args)
              struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
  struct attr *const attr = args->attr;
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  
  /* Flag checks. */ 
  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
 
   /* Length check. */    /* Length check. */
   if (length != 4)    if (length != 4)
     {      {
       zlog (peer->log, LOG_ERR,         zlog (peer->log, LOG_ERR, 
             "MED attribute length isn't four [%d]", length);              "MED attribute length isn't four [%d]", length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 startp, total);                                 args->total);
     }      }
   
   attr->med = stream_getl (peer->ibuf);    attr->med = stream_getl (peer->ibuf);
Line 1056  bgp_attr_med (struct peer *peer, bgp_size_t length,  Line 1293  bgp_attr_med (struct peer *peer, bgp_size_t length, 
   
 /* Local preference attribute. */  /* Local preference attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_local_pref (struct peer *peer, bgp_size_t length, bgp_attr_local_pref (struct bgp_attr_parser_args *args)
                     struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
   struct attr *const attr = args->attr;
   const bgp_size_t length = args->length;
   
   /* Length check. */
   if (length != 4)
   {
     zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
           length);
     return bgp_attr_malformed (args,
                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                args->total);
   }
   
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  
   /* Flag checks. */  
   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))  
     {  
       zlog (peer->log, LOG_ERR,  
             "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);  
       bgp_notify_send_with_data (peer,  
                                  BGP_NOTIFY_UPDATE_ERR,  
                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,  
                                  startp, total);  
       return -1;  
     }  
   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))  
     {  
       zlog (peer->log, LOG_ERR,  
             "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);  
       bgp_notify_send_with_data (peer,  
                                  BGP_NOTIFY_UPDATE_ERR,  
                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,  
                                  startp, total);  
       return -1;  
     }  
   
   /* If it is contained in an UPDATE message that is received from an    /* If it is contained in an UPDATE message that is received from an
      external peer, then this attribute MUST be ignored by the       external peer, then this attribute MUST be ignored by the
      receiving speaker. */       receiving speaker. */
  if (peer_sort (peer) == BGP_PEER_EBGP)  if (peer->sort == BGP_PEER_EBGP)
     {      {
       stream_forward_getp (peer->ibuf, length);        stream_forward_getp (peer->ibuf, length);
       return BGP_ATTR_PARSE_PROCEED;        return BGP_ATTR_PARSE_PROCEED;
     }      }
   
  if (length == 4)   attr->local_pref = stream_getl (peer->ibuf);
    attr->local_pref = stream_getl (peer->ibuf); 
  else  
    attr->local_pref = 0; 
   
   /* Set atomic aggregate flag. */    /* Set atomic aggregate flag. */
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
Line 1106  bgp_attr_local_pref (struct peer *peer, bgp_size_t len Line 1328  bgp_attr_local_pref (struct peer *peer, bgp_size_t len
   
 /* Atomic aggregate. */  /* Atomic aggregate. */
 static int  static int
bgp_attr_atomic (struct peer *peer, bgp_size_t length, bgp_attr_atomic (struct bgp_attr_parser_args *args)
                 struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
  struct attr *const attr = args->attr;
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  /* Flag checks. */  
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
 
   /* Length check. */    /* Length check. */
   if (length != 0)    if (length != 0)
     {      {
      zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);      zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
            length);
      return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 args->total);
     }      }
   
   /* Set atomic aggregate flag. */    /* Set atomic aggregate flag. */
Line 1162  bgp_attr_atomic (struct peer *peer, bgp_size_t length, Line 1352  bgp_attr_atomic (struct peer *peer, bgp_size_t length,
   
 /* Aggregator attribute */  /* Aggregator attribute */
 static int  static int
bgp_attr_aggregator (struct peer *peer, bgp_size_t length,bgp_attr_aggregator (struct bgp_attr_parser_args *args)
                     struct attr *attr, u_char flag) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
   int wantedlen = 6;    int wantedlen = 6;
   struct attr_extra *attre = bgp_attr_extra_get (attr);    struct attr_extra *attre = bgp_attr_extra_get (attr);
       
Line 1174  bgp_attr_aggregator (struct peer *peer, bgp_size_t len Line 1367  bgp_attr_aggregator (struct peer *peer, bgp_size_t len
       
   if (length != wantedlen)    if (length != wantedlen)
     {      {
      zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);      zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
            wantedlen, length);
      return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 args->total);
     }      }
       
   if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )    if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
Line 1195  bgp_attr_aggregator (struct peer *peer, bgp_size_t len Line 1388  bgp_attr_aggregator (struct peer *peer, bgp_size_t len
   
 /* New Aggregator attribute */  /* New Aggregator attribute */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
                     struct attr *attr, u_char flag                         as_t *as4_aggregator_as,
                     as_t *as4_aggregator_as,                         struct in_addr *as4_aggregator_addr)
                     struct in_addr *as4_aggregator_addr) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
         
   if (length != 8)    if (length != 8)
     {      {
      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
      return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,            length);
       return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 0);
     }      }
     
   *as4_aggregator_as = stream_getl (peer->ibuf);    *as4_aggregator_as = stream_getl (peer->ibuf);
   as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);    as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
   
Line 1218  bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t Line 1416  bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t
 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.  /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
  */   */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,bgp_attr_munge_as4_attrs (struct peer *const peer,
                           struct attr *const attr,
                           struct aspath *as4_path, as_t as4_aggregator,                            struct aspath *as4_path, as_t as4_aggregator,
                           struct in_addr *as4_aggregator_addr)                            struct in_addr *as4_aggregator_addr)
 {  {
   int ignore_as4_path = 0;    int ignore_as4_path = 0;
   struct aspath *newpath;    struct aspath *newpath;
   struct attr_extra *attre = attr->extra;    struct attr_extra *attre = attr->extra;
      
   if (!attr->aspath)
     {
       /* NULL aspath shouldn't be possible as bgp_attr_parse should have
        * checked that all well-known, mandatory attributes were present.
        * 
        * Can only be a problem with peer itself - hard error
        */
       return BGP_ATTR_PARSE_ERROR;
     }
   
   if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))    if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
     {      {
       /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR        /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
Line 1247  bgp_attr_munge_as4_attrs (struct peer *peer, struct at Line 1456  bgp_attr_munge_as4_attrs (struct peer *peer, struct at
       return BGP_ATTR_PARSE_PROCEED;        return BGP_ATTR_PARSE_PROCEED;
     }      }
       
   if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))  
       && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))  
     {  
       /* Hu? This is not supposed to happen at all!  
        * got as4_path and no aspath,  
        *   This should already  
        *   have been handled by 'well known attributes missing'  
        *   But... yeah, paranoia  
        * Take this as a "malformed attribute"  
        */  
       zlog (peer->log, LOG_ERR,   
             "%s BGP not AS4 capable peer sent AS4_PATH but"  
             " no AS_PATH, cant do anything here", peer->host);  
       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,  
                                  BGP_NOTIFY_UPDATE_MAL_ATTR,  
                                  NULL, 0);  
     }  
   
   /* We have a asn16 peer.  First, look for AS4_AGGREGATOR    /* We have a asn16 peer.  First, look for AS4_AGGREGATOR
    * because that may override AS4_PATH     * because that may override AS4_PATH
    */     */
Line 1323  bgp_attr_munge_as4_attrs (struct peer *peer, struct at Line 1514  bgp_attr_munge_as4_attrs (struct peer *peer, struct at
   /* need to reconcile NEW_AS_PATH and AS_PATH */    /* need to reconcile NEW_AS_PATH and AS_PATH */
   if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))    if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
     {      {
       newpath = aspath_reconcile_as4 (attr->aspath, as4_path);      newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
       aspath_unintern (&attr->aspath);      aspath_unintern (&attr->aspath);
       attr->aspath = aspath_intern (newpath);      attr->aspath = aspath_intern (newpath);
     }      }
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
 /* Community attribute. */  /* Community attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_community (struct peer *peer, bgp_size_t length, bgp_attr_community (struct bgp_attr_parser_args *args)
                    struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total  struct peer *const peer = args->peer; 
    = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  struct attr *const attr = args->attr;  
   const bgp_size_t length = args->length;
       
   if (length == 0)    if (length == 0)
     {      {
Line 1351  bgp_attr_community (struct peer *peer, bgp_size_t leng Line 1542  bgp_attr_community (struct peer *peer, bgp_size_t leng
   stream_forward_getp (peer->ibuf, length);    stream_forward_getp (peer->ibuf, length);
   
   if (!attr->community)    if (!attr->community)
    return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,    return bgp_attr_malformed (args,
                                BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                               startp, total);                               args->total);
       
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
   
Line 1362  bgp_attr_community (struct peer *peer, bgp_size_t leng Line 1553  bgp_attr_community (struct peer *peer, bgp_size_t leng
   
 /* Originator ID attribute. */  /* Originator ID attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_originator_id (struct peer *peer, bgp_size_t length, bgp_attr_originator_id (struct bgp_attr_parser_args *args)
                        struct attr *attr, u_char flag) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
     /* Length check. */
   if (length != 4)    if (length != 4)
     {      {
       zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);        zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 args->total);
     }      }
   
   (bgp_attr_extra_get (attr))->originator_id.s_addr     (bgp_attr_extra_get (attr))->originator_id.s_addr 
Line 1384  bgp_attr_originator_id (struct peer *peer, bgp_size_t  Line 1579  bgp_attr_originator_id (struct peer *peer, bgp_size_t 
   
 /* Cluster list attribute. */  /* Cluster list attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
                       struct attr *attr, u_char flag) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
   /* Check length. */    /* Check length. */
   if (length % 4)    if (length % 4)
     {      {
       zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);        zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,      return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                 args->total);
                                 NULL, 0); 
     }      }
   
   (bgp_attr_extra_get (attr))->cluster     (bgp_attr_extra_get (attr))->cluster 
Line 1410  bgp_attr_cluster_list (struct peer *peer, bgp_size_t l Line 1607  bgp_attr_cluster_list (struct peer *peer, bgp_size_t l
   
 /* Multiprotocol reachability information parse. */  /* Multiprotocol reachability information parse. */
 int  int
bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
                    struct bgp_nlri *mp_update)                    struct bgp_nlri *mp_update)
 {  {
   afi_t afi;    afi_t afi;
   safi_t safi;    safi_t safi;
   bgp_size_t nlri_len;    bgp_size_t nlri_len;
   size_t start;    size_t start;
   int ret;  
   struct stream *s;    struct stream *s;
     struct peer *const peer = args->peer;  
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
   struct attr_extra *attre = bgp_attr_extra_get(attr);    struct attr_extra *attre = bgp_attr_extra_get(attr);
       
   /* Set end of packet. */    /* Set end of packet. */
Line 1432  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1631  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
     {      {
       zlog_info ("%s: %s sent invalid length, %lu",         zlog_info ("%s: %s sent invalid length, %lu", 
                  __func__, peer->host, (unsigned long)length);                   __func__, peer->host, (unsigned long)length);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
       
   /* Load AFI, SAFI. */    /* Load AFI, SAFI. */
Line 1446  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1645  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
     {      {
       zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",         zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", 
                  __func__, peer->host, attre->mp_nexthop_len);                   __func__, peer->host, attre->mp_nexthop_len);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
       
   /* Nexthop length check. */    /* Nexthop length check. */
Line 1459  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1658  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
         memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);          memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
       break;        break;
     case 12:      case 12:
         stream_getl (s); /* RD high */
         stream_getl (s); /* RD low */
         stream_get (&attre->mp_nexthop_global_in, s, 4);
         break;
       case 24:
       {        {
        u_int32_t rd_high;        u_int32_t rd_high __attribute__((unused));
        u_int32_t rd_low;        u_int32_t rd_low __attribute__((unused));
   
        rd_high = stream_getl (s);        rd_high = stream_getl (s);
        rd_low = stream_getl (s);        rd_low = stream_getl (s);
        stream_get (&attre->mp_nexthop_global_in, s, 4); 
       }        }
      break;      /* fall through */
#ifdef HAVE_IPV6 
     case 16:      case 16:
       stream_get (&attre->mp_nexthop_global, s, 16);        stream_get (&attre->mp_nexthop_global, s, 16);
       break;        break;
     case 32:      case 32:
       case 48:
         if (attre->mp_nexthop_len == 48) {
           u_int32_t rd_high __attribute__((unused));
           u_int32_t rd_low __attribute__((unused));
   
           rd_high = stream_getl (s);
           rd_low = stream_getl (s);
         }
       stream_get (&attre->mp_nexthop_global, s, 16);        stream_get (&attre->mp_nexthop_global, s, 16);
   
         if (attre->mp_nexthop_len == 48) {
           u_int32_t rd_high __attribute__((unused));
           u_int32_t rd_low __attribute__((unused));
   
           rd_high = stream_getl (s);
           rd_low = stream_getl (s);
         }
       stream_get (&attre->mp_nexthop_local, s, 16);        stream_get (&attre->mp_nexthop_local, s, 16);
       if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))        if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
         {          {
Line 1490  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1708  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
           attre->mp_nexthop_len = 16;            attre->mp_nexthop_len = 16;
         }          }
       break;        break;
 #endif /* HAVE_IPV6 */  
     default:      default:
       zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",         zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", 
                  __func__, peer->host, attre->mp_nexthop_len);                   __func__, peer->host, attre->mp_nexthop_len);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
   
   if (!LEN_LEFT)    if (!LEN_LEFT)
     {      {
       zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",        zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
                  __func__, peer->host);                   __func__, peer->host);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
       
   {    {
Line 1517  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1734  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
     {      {
       zlog_info ("%s: (%s) Failed to read NLRI",        zlog_info ("%s: (%s) Failed to read NLRI",
                  __func__, peer->host);                   __func__, peer->host);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
   
  if (safi != BGP_SAFI_VPNV4) 
    { 
      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); 
      if (ret < 0)  
        { 
          zlog_info ("%s: (%s) NLRI doesn't pass sanity check", 
                     __func__, peer->host); 
          return BGP_ATTR_PARSE_ERROR; 
        } 
    } 
 
   mp_update->afi = afi;    mp_update->afi = afi;
   mp_update->safi = safi;    mp_update->safi = safi;
   mp_update->nlri = stream_pnt (s);    mp_update->nlri = stream_pnt (s);
Line 1538  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1744  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
   
   stream_forward_getp (s, nlri_len);    stream_forward_getp (s, nlri_len);
   
     attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 #undef LEN_LEFT  #undef LEN_LEFT
 }  }
   
 /* Multiprotocol unreachable parse */  /* Multiprotocol unreachable parse */
 int  int
bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
                       struct bgp_nlri *mp_withdraw)                        struct bgp_nlri *mp_withdraw)
 {  {
   struct stream *s;    struct stream *s;
   afi_t afi;    afi_t afi;
   safi_t safi;    safi_t safi;
   u_int16_t withdraw_len;    u_int16_t withdraw_len;
  int ret;  struct peer *const peer = args->peer;  
   struct attr *const attr = args->attr;
   const bgp_size_t length = args->length;
   
   s = peer->ibuf;    s = peer->ibuf;
       
 #define BGP_MP_UNREACH_MIN_SIZE 3  #define BGP_MP_UNREACH_MIN_SIZE 3
   if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE))    if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE))
    return BGP_ATTR_PARSE_ERROR;    return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
       
   afi = stream_getw (s);    afi = stream_getw (s);
   safi = stream_getc (s);    safi = stream_getc (s);
       
   withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;    withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
   
   if (safi != BGP_SAFI_VPNV4)  
     {  
       ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);  
       if (ret < 0)  
         return BGP_ATTR_PARSE_ERROR;  
     }  
   
   mp_withdraw->afi = afi;    mp_withdraw->afi = afi;
   mp_withdraw->safi = safi;    mp_withdraw->safi = safi;
   mp_withdraw->nlri = stream_pnt (s);    mp_withdraw->nlri = stream_pnt (s);
Line 1578  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le Line 1781  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
   
   stream_forward_getp (s, withdraw_len);    stream_forward_getp (s, withdraw_len);
   
     attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
 /* Extended Community attribute. */  /* Extended Community attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
                          struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total  struct peer *const peer = args->peer;  
    = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  struct attr *const attr = args->attr;  
   const bgp_size_t length = args->length;
       
   if (length == 0)    if (length == 0)
     {      {
Line 1603  bgp_attr_ext_communities (struct peer *peer, bgp_size_ Line 1808  bgp_attr_ext_communities (struct peer *peer, bgp_size_
   stream_forward_getp (peer->ibuf, length);    stream_forward_getp (peer->ibuf, length);
       
   if (!attr->extra->ecommunity)    if (!attr->extra->ecommunity)
    return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,    return bgp_attr_malformed (args,
                               flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                               startp, total);                               args->total);
       
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
   /* Parse Tunnel Encap attribute in an UPDATE */
   static int
   bgp_attr_encap(
     uint8_t       type,
     struct peer   *peer,  /* IN */
     bgp_size_t    length, /* IN: attr's length field */
     struct attr   *attr,  /* IN: caller already allocated */
     u_char        flag,   /* IN: attr's flags field */
     u_char        *startp)
   {
     bgp_size_t                    total;
     struct attr_extra             *attre = NULL;
     struct bgp_attr_encap_subtlv  *stlv_last = NULL;
     uint16_t                      tunneltype;
   
     total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
   
     if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
          || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
       {
         zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute flag isn't optional and transitive %d", flag);
         bgp_notify_send_with_data (peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                                    startp, total);
         return -1;
       }
   
     if (BGP_ATTR_ENCAP == type) {
       /* read outer TLV type and length */
       uint16_t    tlv_length;
   
       if (length < 4) {
           zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute not long enough to contain outer T,L");
           bgp_notify_send_with_data(peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                    startp, total);
           return -1;
       }
       tunneltype = stream_getw (BGP_INPUT (peer));
       tlv_length = stream_getw (BGP_INPUT (peer));
       length -= 4;
   
       if (tlv_length != length) {
           zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)",
               __func__, tlv_length, length);
       }
     }
   
     while (length >= 4) {
       uint16_t    subtype;
       uint16_t    sublength;
       struct bgp_attr_encap_subtlv *tlv;
   
       if (BGP_ATTR_ENCAP == type) {
           subtype   = stream_getc (BGP_INPUT (peer));
           sublength = stream_getc (BGP_INPUT (peer));
           length   -= 2;
       }
   
       if (sublength > length) {
         zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
               sublength, length);
         bgp_notify_send_with_data (peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                    startp, total);
         return -1;
       }
   
       /* alloc and copy sub-tlv */
       /* TBD make sure these are freed when attributes are released */
       tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength);
       tlv->type = subtype;
       tlv->length = sublength;
       stream_get(tlv->value, peer->ibuf, sublength);
       length -= sublength;
   
       /* attach tlv to encap chain */
       if (!attre) {
           attre = bgp_attr_extra_get(attr);
           if (BGP_ATTR_ENCAP == type) {
               for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next;
                   stlv_last = stlv_last->next);
               if (stlv_last) {
                   stlv_last->next = tlv;
               } else {
                   attre->encap_subtlvs = tlv;
               }
           }
       } else {
           stlv_last->next = tlv;
       }
       stlv_last = tlv;
     }
   
     if (attre && (BGP_ATTR_ENCAP == type)) {
         attre->encap_tunneltype = tunneltype;
     }
   
     if (length) {
       /* spurious leftover data */
         zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute length is bad: %d leftover octets", length);
         bgp_notify_send_with_data (peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                    startp, total);
         return -1;
     }
   
     return 0;
   }
   
 /* BGP unknown attribute treatment. */  /* BGP unknown attribute treatment. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,bgp_attr_unknown (struct bgp_attr_parser_args *args)
                  u_char type, bgp_size_t length, u_char *startp) 
 {  {
  bgp_size_t total;  bgp_size_t total = args->total;
   struct transit *transit;    struct transit *transit;
   struct attr_extra *attre;    struct attr_extra *attre;
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     u_char *const startp = args->startp;
     const u_char type = args->type;
     const u_char flag = args->flags;  
     const bgp_size_t length = args->length;
     
   
   if (BGP_DEBUG (normal, NORMAL))    if (BGP_DEBUG (normal, NORMAL))
   zlog_debug ("%s Unknown attribute is received (type %d, length %d)",    zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
Line 1632  bgp_attr_unknown (struct peer *peer, struct attr *attr Line 1961  bgp_attr_unknown (struct peer *peer, struct attr *attr
   /* Forward read pointer of input stream. */    /* Forward read pointer of input stream. */
   stream_forward_getp (peer->ibuf, length);    stream_forward_getp (peer->ibuf, length);
   
   /* Adjest total length to include type and length. */  
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  
   
   /* If any of the mandatory well-known attributes are not recognized,    /* If any of the mandatory well-known attributes are not recognized,
      then the Error Subcode is set to Unrecognized Well-known       then the Error Subcode is set to Unrecognized Well-known
      Attribute.  The Data field contains the unrecognized attribute       Attribute.  The Data field contains the unrecognized attribute
      (type, length and value). */       (type, length and value). */
   if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))    if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
     {      {
      return bgp_attr_malformed (peer, type, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_UNREC_ATTR,                                   BGP_NOTIFY_UPDATE_UNREC_ATTR,
                                 startp, total);                                 args->total);
     }      }
   
   /* Unrecognized non-transitive optional attributes must be quietly    /* Unrecognized non-transitive optional attributes must be quietly
Line 1675  bgp_attr_unknown (struct peer *peer, struct attr *attr Line 2001  bgp_attr_unknown (struct peer *peer, struct attr *attr
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
   /* Well-known attribute check. */
   static int
   bgp_attr_check (struct peer *peer, struct attr *attr)
   {
     u_char type = 0;
     
     /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
      * empty UPDATE.  */
     if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
       return BGP_ATTR_PARSE_PROCEED;
     
     /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
        to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
        are present, it should.  Check for any other attribute being present
        instead.
      */
     if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI))
       return BGP_ATTR_PARSE_PROCEED;
     
     if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
       type = BGP_ATTR_ORIGIN;
   
     if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
       type = BGP_ATTR_AS_PATH;
     
     /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and
      * NLRI is empty. We can't easily check NLRI empty here though.
      */
     if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
         && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)))
       type = BGP_ATTR_NEXT_HOP;
     
     if (peer->sort == BGP_PEER_IBGP
         && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
       type = BGP_ATTR_LOCAL_PREF;
   
     if (type)
       {
         zlog (peer->log, LOG_WARNING, 
               "%s Missing well-known attribute %d / %s",
               peer->host, type, LOOKUP (attr_str, type));
         bgp_notify_send_with_data (peer, 
                                    BGP_NOTIFY_UPDATE_ERR, 
                                    BGP_NOTIFY_UPDATE_MISS_ATTR,
                                    &type, 1);
         return BGP_ATTR_PARSE_ERROR;
       }
     return BGP_ATTR_PARSE_PROCEED;
   }
   
 /* Read attribute of update packet.  This function is called from  /* Read attribute of update packet.  This function is called from
   bgp_update() in bgpd.c.  */   bgp_update_receive() in bgp_packet.c.  */
 bgp_attr_parse_ret_t  bgp_attr_parse_ret_t
 bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
                 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)                  struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
Line 1692  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2068  bgp_attr_parse (struct peer *peer, struct attr *attr, 
   /* same goes for as4_aggregator */    /* same goes for as4_aggregator */
   struct aspath *as4_path = NULL;    struct aspath *as4_path = NULL;
   as_t as4_aggregator = 0;    as_t as4_aggregator = 0;
  struct in_addr as4_aggregator_addr = { 0 };  struct in_addr as4_aggregator_addr = { .s_addr = 0 };
   
   /* Initialize bitmap. */    /* Initialize bitmap. */
   memset (seen, 0, BGP_ATTR_BITMAP_SIZE);    memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
Line 1720  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2096  bgp_attr_parse (struct peer *peer, struct attr *attr, 
   
       /* Fetch attribute flag and type. */        /* Fetch attribute flag and type. */
       startp = BGP_INPUT_PNT (peer);        startp = BGP_INPUT_PNT (peer);
      flag = stream_getc (BGP_INPUT (peer));      /* "The lower-order four bits of the Attribute Flags octet are
          unused.  They MUST be zero when sent and MUST be ignored when
          received." */
       flag = 0xF0 & stream_getc (BGP_INPUT (peer));
       type = stream_getc (BGP_INPUT (peer));        type = stream_getc (BGP_INPUT (peer));
   
       /* Check whether Extended-Length applies and is in bounds */        /* Check whether Extended-Length applies and is in bounds */
Line 1737  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2116  bgp_attr_parse (struct peer *peer, struct attr *attr, 
                            BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);                             BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
           return BGP_ATTR_PARSE_ERROR;            return BGP_ATTR_PARSE_ERROR;
         }          }
      
       /* Check extended attribue length bit. */        /* Check extended attribue length bit. */
       if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))        if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
         length = stream_getw (BGP_INPUT (peer));          length = stream_getw (BGP_INPUT (peer));
Line 1777  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2156  bgp_attr_parse (struct peer *peer, struct attr *attr, 
                            BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);                             BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
           return BGP_ATTR_PARSE_ERROR;            return BGP_ATTR_PARSE_ERROR;
         }          }
           
           struct bgp_attr_parser_args attr_args = {
             .peer = peer,
             .length = length,
             .attr = attr,
             .type = type,
             .flags = flag,
             .startp = startp,
             .total = attr_endp - startp,
           };
         
           
         /* If any recognized attribute has Attribute Flags that conflict
            with the Attribute Type Code, then the Error Subcode is set to
            Attribute Flags Error.  The Data field contains the erroneous
            attribute (type, length and value). */
         if (bgp_attr_flag_invalid (&attr_args))
           {
             bgp_attr_parse_ret_t ret;
             ret = bgp_attr_malformed (&attr_args,
                                       BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                                       attr_args.total);
             if (ret == BGP_ATTR_PARSE_PROCEED)
               continue;
             return ret;
           }
   
       /* OK check attribute and store it's value. */        /* OK check attribute and store it's value. */
       switch (type)        switch (type)
         {          {
         case BGP_ATTR_ORIGIN:          case BGP_ATTR_ORIGIN:
          ret = bgp_attr_origin (peer, length, attr, flag, startp);          ret = bgp_attr_origin (&attr_args);
           break;            break;
         case BGP_ATTR_AS_PATH:          case BGP_ATTR_AS_PATH:
          ret = bgp_attr_aspath (peer, length, attr, flag, startp);          ret = bgp_attr_aspath (&attr_args);
           break;            break;
         case BGP_ATTR_AS4_PATH:          case BGP_ATTR_AS4_PATH:
          ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);          ret = bgp_attr_as4_path (&attr_args, &as4_path);
           break;            break;
         case BGP_ATTR_NEXT_HOP:           case BGP_ATTR_NEXT_HOP: 
          ret = bgp_attr_nexthop (peer, length, attr, flag, startp);          ret = bgp_attr_nexthop (&attr_args);
           break;            break;
         case BGP_ATTR_MULTI_EXIT_DISC:          case BGP_ATTR_MULTI_EXIT_DISC:
          ret = bgp_attr_med (peer, length, attr, flag, startp);          ret = bgp_attr_med (&attr_args);
           break;            break;
         case BGP_ATTR_LOCAL_PREF:          case BGP_ATTR_LOCAL_PREF:
          ret = bgp_attr_local_pref (peer, length, attr, flag, startp);          ret = bgp_attr_local_pref (&attr_args);
           break;            break;
         case BGP_ATTR_ATOMIC_AGGREGATE:          case BGP_ATTR_ATOMIC_AGGREGATE:
          ret = bgp_attr_atomic (peer, length, attr, flag, startp);          ret = bgp_attr_atomic (&attr_args);
           break;            break;
         case BGP_ATTR_AGGREGATOR:          case BGP_ATTR_AGGREGATOR:
          ret = bgp_attr_aggregator (peer, length, attr, flag);          ret = bgp_attr_aggregator (&attr_args);
           break;            break;
         case BGP_ATTR_AS4_AGGREGATOR:          case BGP_ATTR_AS4_AGGREGATOR:
          ret = bgp_attr_as4_aggregator (peer, length, attr, flag,          ret = bgp_attr_as4_aggregator (&attr_args,
                                         &as4_aggregator,                                          &as4_aggregator,
                                          &as4_aggregator_addr);                                           &as4_aggregator_addr);
           break;            break;
         case BGP_ATTR_COMMUNITIES:          case BGP_ATTR_COMMUNITIES:
          ret = bgp_attr_community (peer, length, attr, flag, startp);          ret = bgp_attr_community (&attr_args);
           break;            break;
         case BGP_ATTR_ORIGINATOR_ID:          case BGP_ATTR_ORIGINATOR_ID:
          ret = bgp_attr_originator_id (peer, length, attr, flag);          ret = bgp_attr_originator_id (&attr_args);
           break;            break;
         case BGP_ATTR_CLUSTER_LIST:          case BGP_ATTR_CLUSTER_LIST:
          ret = bgp_attr_cluster_list (peer, length, attr, flag);          ret = bgp_attr_cluster_list (&attr_args);
           break;            break;
         case BGP_ATTR_MP_REACH_NLRI:          case BGP_ATTR_MP_REACH_NLRI:
          ret = bgp_mp_reach_parse (peer, length, attr, mp_update);          ret = bgp_mp_reach_parse (&attr_args, mp_update);
           break;            break;
         case BGP_ATTR_MP_UNREACH_NLRI:          case BGP_ATTR_MP_UNREACH_NLRI:
          ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);          ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
           break;            break;
         case BGP_ATTR_EXT_COMMUNITIES:          case BGP_ATTR_EXT_COMMUNITIES:
          ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);          ret = bgp_attr_ext_communities (&attr_args);
           break;            break;
           case BGP_ATTR_ENCAP:
             ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
             break;
         default:          default:
          ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);          ret = bgp_attr_unknown (&attr_args);
           break;            break;
         }          }
               
         if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS)
           {
             bgp_notify_send (peer, 
                              BGP_NOTIFY_UPDATE_ERR,
                              BGP_NOTIFY_UPDATE_MAL_ATTR);
             ret = BGP_ATTR_PARSE_ERROR;
           }
   
       /* If hard error occured immediately return to the caller. */        /* If hard error occured immediately return to the caller. */
       if (ret == BGP_ATTR_PARSE_ERROR)        if (ret == BGP_ATTR_PARSE_ERROR)
         {          {
Line 1840  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2256  bgp_attr_parse (struct peer *peer, struct attr *attr, 
                 "%s: Attribute %s, parse error",                   "%s: Attribute %s, parse error", 
                 peer->host,                   peer->host, 
                 LOOKUP (attr_str, type));                  LOOKUP (attr_str, type));
           bgp_notify_send (peer,   
                            BGP_NOTIFY_UPDATE_ERR,  
                            BGP_NOTIFY_UPDATE_MAL_ATTR);  
           if (as4_path)            if (as4_path)
             aspath_unintern (&as4_path);              aspath_unintern (&as4_path);
           return ret;            return ret;
Line 1873  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2286  bgp_attr_parse (struct peer *peer, struct attr *attr, 
           return BGP_ATTR_PARSE_ERROR;            return BGP_ATTR_PARSE_ERROR;
         }          }
     }      }
   
   /* Check final read pointer is same as end pointer. */    /* Check final read pointer is same as end pointer. */
   if (BGP_INPUT_PNT (peer) != endp)    if (BGP_INPUT_PNT (peer) != endp)
     {      {
Line 1887  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2299  bgp_attr_parse (struct peer *peer, struct attr *attr, 
         aspath_unintern (&as4_path);          aspath_unintern (&as4_path);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
     }      }
  
   /* Check all mandatory well-known attributes are present */
   {
     bgp_attr_parse_ret_t ret;
     if ((ret = bgp_attr_check (peer, attr)) < 0)
       {
         if (as4_path)
           aspath_unintern (&as4_path);
         return ret;
       }
   }
   
   /*     /* 
    * At this place we can see whether we got AS4_PATH and/or     * At this place we can see whether we got AS4_PATH and/or
    * AS4_AGGREGATOR from a 16Bit peer and act accordingly.     * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
Line 1898  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2321  bgp_attr_parse (struct peer *peer, struct attr *attr, 
    * So, to be defensive, we are not relying on any order and read     * So, to be defensive, we are not relying on any order and read
    * all attributes first, including these 32bit ones, and now,     * all attributes first, including these 32bit ones, and now,
    * afterwards, we look what and if something is to be done for as4.     * afterwards, we look what and if something is to be done for as4.
      *
      * It is possible to not have AS_PATH, e.g. GR EoR and sole
      * MP_UNREACH_NLRI.
    */     */
  if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,  /* actually... this doesn't ever return failure currently, but
    * better safe than sorry */
   if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))
       && bgp_attr_munge_as4_attrs (peer, attr, as4_path,
                                 as4_aggregator, &as4_aggregator_addr))                                  as4_aggregator, &as4_aggregator_addr))
     {      {
         bgp_notify_send (peer, 
                          BGP_NOTIFY_UPDATE_ERR,
                          BGP_NOTIFY_UPDATE_MAL_ATTR);
       if (as4_path)        if (as4_path)
         aspath_unintern (&as4_path);          aspath_unintern (&as4_path);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
Line 1931  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2363  bgp_attr_parse (struct peer *peer, struct attr *attr, 
    */     */
   if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))    if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
     {      {
      ret = bgp_attr_aspath_check (peer, attr, flag);      ret = bgp_attr_aspath_check (peer, attr);
       if (ret != BGP_ATTR_PARSE_PROCEED)        if (ret != BGP_ATTR_PARSE_PROCEED)
         return ret;          return ret;
     }      }
Line 1943  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2375  bgp_attr_parse (struct peer *peer, struct attr *attr, 
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
/* Well-known attribute check. */int stream_put_prefix (struct stream *, struct prefix *);
int
bgp_attr_check (struct peer *peer, struct attr *attr)size_t
 bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
                          struct attr *attr)
 {  {
  u_char type = 0;  size_t sizep;
   
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) 
    type = BGP_ATTR_ORIGIN; 
   
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))  /* Set extended bit always to encode the attribute length as 2 bytes */
    type = BGP_ATTR_AS_PATH;  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
   stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
   sizep = stream_get_endp (s);
   stream_putw (s, 0);   /* Marker: Attribute length. */
   
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))  stream_putw (s, afi);
    type = BGP_ATTR_NEXT_HOP;  stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
   
  if (peer_sort (peer) == BGP_PEER_IBGP  /* Nexthop */
      && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))  switch (afi)
    type = BGP_ATTR_LOCAL_PREF;    {
     case AFI_IP:
       switch (safi)
         {
         case SAFI_MULTICAST:
           stream_putc (s, 4);
           stream_put_ipv4 (s, attr->nexthop.s_addr);
           break;
         case SAFI_MPLS_VPN:
           stream_putc (s, 12);
           stream_putl (s, 0);   /* RD = 0, per RFC */
           stream_putl (s, 0);
           stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
           break;
         case SAFI_ENCAP:
           stream_putc (s, 4);
           stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
           break;
         case SAFI_UNICAST:      /* invalid for IPv4 */
         default:
           break;
         }
       break;
     case AFI_IP6:
       switch (safi)
       {
       case SAFI_UNICAST:
       case SAFI_MULTICAST:
         {
           struct attr_extra *attre = attr->extra;
   
  if (type)          assert (attr->extra);
           stream_putc (s, attre->mp_nexthop_len);
           stream_put (s, &attre->mp_nexthop_global, 16);
           if (attre->mp_nexthop_len == 32)
             stream_put (s, &attre->mp_nexthop_local, 16);
         }
         break;
       case SAFI_MPLS_VPN:
         {
           struct attr_extra *attre = attr->extra;
 
           assert (attr->extra);
           if (attre->mp_nexthop_len == 16) {
             stream_putc (s, 24);
             stream_putl (s, 0);   /* RD = 0, per RFC */
             stream_putl (s, 0);
             stream_put (s, &attre->mp_nexthop_global, 16);
           } else if (attre->mp_nexthop_len == 32) {
             stream_putc (s, 48);
             stream_putl (s, 0);   /* RD = 0, per RFC */
             stream_putl (s, 0);
             stream_put (s, &attre->mp_nexthop_global, 16);
             stream_putl (s, 0);   /* RD = 0, per RFC */
             stream_putl (s, 0);
             stream_put (s, &attre->mp_nexthop_local, 16);
           }
         }
         break;
         case SAFI_ENCAP:
           assert (attr->extra);
           stream_putc (s, 16);
           stream_put (s, &attr->extra->mp_nexthop_global, 16);
           break;
       default:
         break;
       }
       break;
     default:
       break;
     }
 
   /* SNPA */
   stream_putc (s, 0);
   return sizep;
 }
 
 void
 bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
                           struct prefix *p, struct prefix_rd *prd,
                           u_char *tag)
 {
   if (safi == SAFI_MPLS_VPN)
     {      {
      zlog (peer->log, LOG_WARNING,       /* Tag, RD, Prefix write. */
            "%s Missing well-known attribute %d.",      stream_putc (s, p->prefixlen + 88);
            peer->host, type);      stream_put (s, tag, 3);
      bgp_notify_send_with_data (peer,       stream_put (s, prd->val, 8);
                                 BGP_NOTIFY_UPDATE_ERR,       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
                                 BGP_NOTIFY_UPDATE_MISS_ATTR, 
                                 &type, 1); 
      return BGP_ATTR_PARSE_ERROR; 
     }      }
  return BGP_ATTR_PARSE_PROCEED;  else
     stream_put_prefix (s, p);
 }  }
   
 int stream_put_prefix (struct stream *, struct prefix *);  
   
   size_t
   bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p)
   {
     int size = PSIZE (p->prefixlen);
     if (safi == SAFI_MPLS_VPN)
         size += 88;
     return size;
   }
   
   /*
    * Encodes the tunnel encapsulation attribute
    */
   static void
   bgp_packet_mpattr_tea(
       struct bgp          *bgp,
       struct peer         *peer,
       struct stream       *s,
       struct attr         *attr,
       uint8_t             attrtype)
   {
       unsigned int                        attrlenfield = 0;
       unsigned int                        attrhdrlen   = 0;
       struct bgp_attr_encap_subtlv        *subtlvs;
       struct bgp_attr_encap_subtlv        *st;
       const char                          *attrname;
   
       if (!attr || !attr->extra)
           return;
   
       switch (attrtype) {
           case BGP_ATTR_ENCAP:
               attrname = "Tunnel Encap";
               subtlvs = attr->extra->encap_subtlvs;
   
               /*
                * The tunnel encap attr has an "outer" tlv.
                * T = tunneltype,
                * L = total length of subtlvs,
                * V = concatenated subtlvs.
                */
               attrlenfield = 2 + 2;       /* T + L */
               attrhdrlen   = 1 + 1;       /* subTLV T + L */
               break;
   
           default:
               assert(0);
       }
   
   
       /* if no tlvs, don't make attr */
       if (subtlvs == NULL)
           return;
   
       /* compute attr length */
       for (st = subtlvs; st; st = st->next) {
           attrlenfield += (attrhdrlen + st->length);
       }
   
       if (attrlenfield > 0xffff) {
           zlog (peer->log, LOG_ERR,
               "%s attribute is too long (length=%d), can't send it",
               attrname,
               attrlenfield);
           return;
       }
   
       if (attrlenfield > 0xff) {
           /* 2-octet length field */
           stream_putc (s,
               BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
           stream_putc (s, attrtype);
           stream_putw (s, attrlenfield & 0xffff);
       } else {
           /* 1-octet length field */
           stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
           stream_putc (s, attrtype);
           stream_putc (s, attrlenfield & 0xff);
       }
   
       if (attrtype == BGP_ATTR_ENCAP) {
           /* write outer T+L */
           stream_putw(s, attr->extra->encap_tunneltype);
           stream_putw(s, attrlenfield - 4);
       }
   
       /* write each sub-tlv */
       for (st = subtlvs; st; st = st->next) {
           if (attrtype == BGP_ATTR_ENCAP) {
               stream_putc (s, st->type);
               stream_putc (s, st->length);
           }
           stream_put (s, st->value, st->length);
       }
   }
   
   void
   bgp_packet_mpattr_end (struct stream *s, size_t sizep)
   {
     /* Set MP attribute length. Don't count the (2) bytes used to encode
        the attr length */
     stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2);
   }
   
 /* Make attribute packet. */  /* Make attribute packet. */
 bgp_size_t  bgp_size_t
 bgp_packet_attribute (struct bgp *bgp, struct peer *peer,  bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
                      struct stream *s, struct attr *attr, struct prefix *p,                      struct stream *s, struct attr *attr,
                      afi_t afi, safi_t safi, struct peer *from,                      struct prefix *p, afi_t afi, safi_t safi,
                      struct prefix_rd *prd, u_char *tag)                      struct peer *from, struct prefix_rd *prd, u_char *tag)
 {  {
   size_t cp;    size_t cp;
   size_t aspath_sizep;    size_t aspath_sizep;
Line 1998  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2611  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
   /* Remember current pointer. */    /* Remember current pointer. */
   cp = stream_get_endp (s);    cp = stream_get_endp (s);
   
     if (p && !(afi == AFI_IP && safi == SAFI_UNICAST))
       {
         size_t mpattrlen_pos = 0;
         mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr);
         bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
         bgp_packet_mpattr_end(s, mpattrlen_pos);
       }
   
   /* Origin attribute. */    /* Origin attribute. */
   stream_putc (s, BGP_ATTR_FLAG_TRANS);    stream_putc (s, BGP_ATTR_FLAG_TRANS);
   stream_putc (s, BGP_ATTR_ORIGIN);    stream_putc (s, BGP_ATTR_ORIGIN);
Line 2007  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2628  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
   /* AS path attribute. */    /* AS path attribute. */
   
   /* If remote-peer is EBGP */    /* If remote-peer is EBGP */
  if (peer_sort (peer) == BGP_PEER_EBGP  if (peer->sort == BGP_PEER_EBGP
       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)        && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
           || attr->aspath->segments == NULL)            || attr->aspath->segments == NULL)
       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))        && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
Line 2023  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2644  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
         }          }
       else        else
         {          {
          aspath = aspath_add_seq (aspath, peer->local_as);          if (peer->change_local_as) {
          if (peer->change_local_as)            /* If replace-as is specified, we only use the change_local_as when
                advertising routes. */
             if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
               aspath = aspath_add_seq (aspath, peer->local_as);
             }
             aspath = aspath_add_seq (aspath, peer->change_local_as);              aspath = aspath_add_seq (aspath, peer->change_local_as);
             } else {
               aspath = aspath_add_seq (aspath, peer->local_as);
             }
         }          }
     }      }
  else if (peer_sort (peer) == BGP_PEER_CONFED)  else if (peer->sort == BGP_PEER_CONFED)
     {      {
       /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */        /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
       aspath = aspath_dup (attr->aspath);        aspath = aspath_dup (attr->aspath);
Line 2059  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2687  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
       send_as4_path = 1; /* we'll do this later, at the correct place */        send_as4_path = 1; /* we'll do this later, at the correct place */
       
   /* Nexthop attribute. */    /* Nexthop attribute. */
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP &&
     safi ==  SAFI_UNICAST)   /* only write NH attr for unicast safi */
     {      {
       stream_putc (s, BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_FLAG_TRANS);
       stream_putc (s, BGP_ATTR_NEXT_HOP);        stream_putc (s, BGP_ATTR_NEXT_HOP);
Line 2085  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2714  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
     }      }
   
   /* Local preference. */    /* Local preference. */
  if (peer_sort (peer) == BGP_PEER_IBGP ||  if (peer->sort == BGP_PEER_IBGP ||
      peer_sort (peer) == BGP_PEER_CONFED)      peer->sort == BGP_PEER_CONFED)
     {      {
       stream_putc (s, BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_FLAG_TRANS);
       stream_putc (s, BGP_ATTR_LOCAL_PREF);        stream_putc (s, BGP_ATTR_LOCAL_PREF);
Line 2159  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2788  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
     }      }
   
   /* Route Reflector. */    /* Route Reflector. */
  if (peer_sort (peer) == BGP_PEER_IBGP  if (peer->sort == BGP_PEER_IBGP
       && from        && from
      && peer_sort (from) == BGP_PEER_IBGP)      && from->sort == BGP_PEER_IBGP)
     {      {
       /* Originator ID. */        /* Originator ID. */
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);        stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
Line 2199  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2828  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
         }          }
     }      }
   
 #ifdef HAVE_IPV6  
   /* If p is IPv6 address put it into attribute. */  
   if (p->family == AF_INET6)  
     {  
       unsigned long sizep;  
       struct attr_extra *attre = attr->extra;  
         
       assert (attr->extra);  
         
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);  
       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);  
       sizep = stream_get_endp (s);  
       stream_putc (s, 0);       /* Marker: Attribute length. */  
       stream_putw (s, AFI_IP6); /* AFI */  
       stream_putc (s, safi);    /* SAFI */  
   
       stream_putc (s, attre->mp_nexthop_len);  
   
       if (attre->mp_nexthop_len == 16)  
         stream_put (s, &attre->mp_nexthop_global, 16);  
       else if (attre->mp_nexthop_len == 32)  
         {  
           stream_put (s, &attre->mp_nexthop_global, 16);  
           stream_put (s, &attre->mp_nexthop_local, 16);  
         }  
         
       /* SNPA */  
       stream_putc (s, 0);  
   
       /* Prefix write. */  
       stream_put_prefix (s, p);  
   
       /* Set MP attribute length. */  
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);  
     }  
 #endif /* HAVE_IPV6 */  
   
   if (p->family == AF_INET && safi == SAFI_MULTICAST)  
     {  
       unsigned long sizep;  
   
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);  
       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);  
       sizep = stream_get_endp (s);  
       stream_putc (s, 0);       /* Marker: Attribute Length. */  
       stream_putw (s, AFI_IP);  /* AFI */  
       stream_putc (s, SAFI_MULTICAST);  /* SAFI */  
   
       stream_putc (s, 4);  
       stream_put_ipv4 (s, attr->nexthop.s_addr);  
   
       /* SNPA */  
       stream_putc (s, 0);  
   
       /* Prefix write. */  
       stream_put_prefix (s, p);  
   
       /* Set MP attribute length. */  
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);  
     }  
   
   if (p->family == AF_INET && safi == SAFI_MPLS_VPN)  
     {  
       unsigned long sizep;  
   
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);  
       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);  
       sizep = stream_get_endp (s);  
       stream_putc (s, 0);       /* Length of this attribute. */  
       stream_putw (s, AFI_IP);  /* AFI */  
       stream_putc (s, BGP_SAFI_VPNV4);  /* SAFI */  
   
       stream_putc (s, 12);  
       stream_putl (s, 0);  
       stream_putl (s, 0);  
       stream_put (s, &attr->extra->mp_nexthop_global_in, 4);  
   
       /* SNPA */  
       stream_putc (s, 0);  
   
       /* Tag, RD, Prefix write. */  
       stream_putc (s, p->prefixlen + 88);  
       stream_put (s, tag, 3);  
       stream_put (s, prd->val, 8);  
       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));  
   
       /* Set MP attribute length. */  
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);  
     }  
   
   /* Extended Communities attribute. */    /* Extended Communities attribute. */
   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)     if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) 
       && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))        && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
Line 2297  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2836  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
               
       assert (attre);        assert (attre);
               
      if (peer_sort (peer) == BGP_PEER_IBGP       if (peer->sort == BGP_PEER_IBGP
          || peer_sort (peer) == BGP_PEER_CONFED)          || peer->sort == BGP_PEER_CONFED)
         {          {
           if (attre->ecommunity->size * 8 > 255)            if (attre->ecommunity->size * 8 > 255)
             {              {
Line 2401  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2940  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
       stream_putl (s, attr->extra->aggregator_as);        stream_putl (s, attr->extra->aggregator_as);
       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);        stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
     }      }
  
   if ((afi == AFI_IP || afi == AFI_IP6) &&
       (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
     {
         /* Tunnel Encap attribute */
         bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
     }
 
   /* Unknown transit attribute. */    /* Unknown transit attribute. */
   if (attr->extra && attr->extra->transit)    if (attr->extra && attr->extra->transit)
     stream_put (s, attr->extra->transit->val, attr->extra->transit->length);      stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
Line 2410  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2956  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
   return stream_get_endp (s) - cp;    return stream_get_endp (s) - cp;
 }  }
   
bgp_size_tsize_t
bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
                     afi_t afi, safi_t safi, struct prefix_rd *prd, 
                     u_char *tag) 
 {  {
   unsigned long cp;  
   unsigned long attrlen_pnt;    unsigned long attrlen_pnt;
   bgp_size_t size;  
   
  cp = stream_get_endp (s);  /* Set extended bit always to encode the attribute length as 2 bytes */
  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); 
   stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);    stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
   
   attrlen_pnt = stream_get_endp (s);    attrlen_pnt = stream_get_endp (s);
  stream_putc (s, 0);                /* Length of this attribute. */  stream_putw (s, 0);                /* Length of this attribute. */
   
  stream_putw (s, family2afi (p->family));  stream_putw (s, afi);
   stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
   return attrlen_pnt;
 }
   
  if (safi == SAFI_MPLS_VPN)void
    {bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
      /* SAFI */                             afi_t afi, safi_t safi, struct prefix_rd *prd,
      stream_putc (s, BGP_SAFI_VPNV4);                             u_char *tag)
 {
   bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag);
 }
   
      /* prefix. */void
      stream_putc (s, p->prefixlen + 88);bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt)
      stream_put (s, tag, 3);{
      stream_put (s, prd->val, 8);  bgp_packet_mpattr_end (s, attrlen_pnt);
      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); 
    } 
  else 
    { 
      /* SAFI */ 
      stream_putc (s, safi); 
 
      /* prefix */ 
      stream_put_prefix (s, p); 
    } 
 
  /* Set MP attribute length. */ 
  size = stream_get_endp (s) - attrlen_pnt - 1; 
  stream_putc_at (s, attrlen_pnt, size); 
 
  return stream_get_endp (s) - cp; 
 }  }
   
 /* Initialization of attribute. */  /* Initialization of attribute. */
Line 2513  bgp_dump_routes_attr (struct stream *s, struct attr *a Line 3044  bgp_dump_routes_attr (struct stream *s, struct attr *a
   /* Nexthop attribute. */    /* Nexthop attribute. */
   /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */    /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
   if(prefix != NULL    if(prefix != NULL
 #ifdef HAVE_IPV6  
      && prefix->family != AF_INET6       && prefix->family != AF_INET6
 #endif /* HAVE_IPV6 */  
      )       )
     {      {
       stream_putc (s, BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_FLAG_TRANS);
Line 2579  bgp_dump_routes_attr (struct stream *s, struct attr *a Line 3108  bgp_dump_routes_attr (struct stream *s, struct attr *a
       stream_put (s, attr->community->val, attr->community->size * 4);        stream_put (s, attr->community->val, attr->community->size * 4);
     }      }
   
 #ifdef HAVE_IPV6  
   /* Add a MP_NLRI attribute to dump the IPv6 next hop */    /* Add a MP_NLRI attribute to dump the IPv6 next hop */
   if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&    if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
      (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )       (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
Line 2611  bgp_dump_routes_attr (struct stream *s, struct attr *a Line 3139  bgp_dump_routes_attr (struct stream *s, struct attr *a
       /* Set MP attribute length. */        /* Set MP attribute length. */
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);        stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
     }      }
 #endif /* HAVE_IPV6 */  
   
   /* Return total size of attribute. */    /* Return total size of attribute. */
   len = stream_get_endp (s) - cp - 2;    len = stream_get_endp (s) - cp - 2;

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>