Annotation of embedaddon/quagga/bgpd/bgp_attr.c, revision 1.1.1.4

1.1       misho       1: /* BGP attributes management routines.
                      2:    Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
                      3: 
                      4: This file is part of GNU Zebra.
                      5: 
                      6: GNU Zebra is free software; you can redistribute it and/or modify it
                      7: under the terms of the GNU General Public License as published by the
                      8: Free Software Foundation; either version 2, or (at your option) any
                      9: later version.
                     10: 
                     11: GNU Zebra is distributed in the hope that it will be useful, but
                     12: WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     14: General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU Zebra; see the file COPYING.  If not, write to the Free
                     18: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
                     19: 02111-1307, USA.  */
                     20: 
                     21: #include <zebra.h>
                     22: 
                     23: #include "linklist.h"
                     24: #include "prefix.h"
                     25: #include "memory.h"
                     26: #include "vector.h"
                     27: #include "vty.h"
                     28: #include "stream.h"
                     29: #include "log.h"
                     30: #include "hash.h"
                     31: #include "jhash.h"
1.1.1.4 ! misho      32: #include "filter.h"
1.1       misho      33: 
                     34: #include "bgpd/bgpd.h"
                     35: #include "bgpd/bgp_attr.h"
                     36: #include "bgpd/bgp_route.h"
                     37: #include "bgpd/bgp_aspath.h"
                     38: #include "bgpd/bgp_community.h"
                     39: #include "bgpd/bgp_debug.h"
                     40: #include "bgpd/bgp_packet.h"
                     41: #include "bgpd/bgp_ecommunity.h"
1.1.1.4 ! misho      42: #include "table.h"
        !            43: #include "bgp_encap_types.h"
        !            44: 
1.1       misho      45: /* Attribute strings for logging. */
                     46: static const struct message attr_str [] = 
                     47: {
                     48:   { BGP_ATTR_ORIGIN,           "ORIGIN" }, 
                     49:   { BGP_ATTR_AS_PATH,          "AS_PATH" }, 
                     50:   { BGP_ATTR_NEXT_HOP,         "NEXT_HOP" }, 
                     51:   { BGP_ATTR_MULTI_EXIT_DISC,  "MULTI_EXIT_DISC" }, 
                     52:   { BGP_ATTR_LOCAL_PREF,       "LOCAL_PREF" }, 
                     53:   { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, 
                     54:   { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" }, 
                     55:   { BGP_ATTR_COMMUNITIES,      "COMMUNITY" }, 
                     56:   { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },
1.1.1.2   misho      57:   { BGP_ATTR_CLUSTER_LIST,     "CLUSTER_LIST" }, 
1.1       misho      58:   { BGP_ATTR_DPA,              "DPA" },
                     59:   { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,
                     60:   { BGP_ATTR_RCID_PATH,        "RCID_PATH" },
                     61:   { BGP_ATTR_MP_REACH_NLRI,    "MP_REACH_NLRI" },
                     62:   { BGP_ATTR_MP_UNREACH_NLRI,  "MP_UNREACH_NLRI" },
                     63:   { BGP_ATTR_EXT_COMMUNITIES,  "EXT_COMMUNITIES" },
                     64:   { BGP_ATTR_AS4_PATH,         "AS4_PATH" }, 
                     65:   { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" }, 
                     66:   { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },
1.1.1.4 ! misho      67:   { BGP_ATTR_ENCAP,            "ENCAP" },
1.1       misho      68: };
1.1.1.3   misho      69: static const int attr_str_max = array_size(attr_str);
1.1.1.2   misho      70: 
                     71: static const struct message attr_flag_str[] =
                     72: {
                     73:   { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
                     74:   { BGP_ATTR_FLAG_TRANS,    "Transitive" },
                     75:   { BGP_ATTR_FLAG_PARTIAL,  "Partial" },
                     76:   /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
                     77:   { BGP_ATTR_FLAG_EXTLEN,   "Extended Length" },
                     78: };
1.1.1.4 ! misho      79: 
1.1       misho      80: static struct hash *cluster_hash;
                     81: 
                     82: static void *
                     83: cluster_hash_alloc (void *p)
                     84: {
                     85:   struct cluster_list * val = (struct cluster_list *) p;
                     86:   struct cluster_list *cluster;
                     87: 
                     88:   cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
                     89:   cluster->length = val->length;
                     90: 
                     91:   if (cluster->length)
                     92:     {
                     93:       cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
                     94:       memcpy (cluster->list, val->list, val->length);
                     95:     }
                     96:   else
                     97:     cluster->list = NULL;
                     98: 
                     99:   cluster->refcnt = 0;
                    100: 
                    101:   return cluster;
                    102: }
                    103: 
                    104: /* Cluster list related functions. */
                    105: static struct cluster_list *
                    106: cluster_parse (struct in_addr * pnt, int length)
                    107: {
                    108:   struct cluster_list tmp;
                    109:   struct cluster_list *cluster;
                    110: 
                    111:   tmp.length = length;
                    112:   tmp.list = pnt;
                    113: 
                    114:   cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
                    115:   cluster->refcnt++;
                    116:   return cluster;
                    117: }
                    118: 
                    119: int
                    120: cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
                    121: {
                    122:   int i;
                    123:     
                    124:   for (i = 0; i < cluster->length / 4; i++)
                    125:     if (cluster->list[i].s_addr == originator.s_addr)
                    126:       return 1;
                    127:   return 0;
                    128: }
                    129: 
                    130: static unsigned int
                    131: cluster_hash_key_make (void *p)
                    132: {
                    133:   const struct cluster_list *cluster = p;
                    134: 
                    135:   return jhash(cluster->list, cluster->length, 0);
                    136: }
                    137: 
                    138: static int
                    139: cluster_hash_cmp (const void *p1, const void *p2)
                    140: {
                    141:   const struct cluster_list * cluster1 = p1;
                    142:   const struct cluster_list * cluster2 = p2;
                    143: 
                    144:   return (cluster1->length == cluster2->length &&
                    145:          memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
                    146: }
                    147: 
                    148: static void
                    149: cluster_free (struct cluster_list *cluster)
                    150: {
                    151:   if (cluster->list)
                    152:     XFREE (MTYPE_CLUSTER_VAL, cluster->list);
                    153:   XFREE (MTYPE_CLUSTER, cluster);
                    154: }
                    155: 
                    156: #if 0
                    157: static struct cluster_list *
                    158: cluster_dup (struct cluster_list *cluster)
                    159: {
                    160:   struct cluster_list *new;
                    161: 
                    162:   new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
                    163:   new->length = cluster->length;
                    164: 
                    165:   if (cluster->length)
                    166:     {
                    167:       new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
                    168:       memcpy (new->list, cluster->list, cluster->length);
                    169:     }
                    170:   else
                    171:     new->list = NULL;
                    172:   
                    173:   return new;
                    174: }
                    175: #endif
                    176: 
                    177: static struct cluster_list *
                    178: cluster_intern (struct cluster_list *cluster)
                    179: {
                    180:   struct cluster_list *find;
                    181: 
                    182:   find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
                    183:   find->refcnt++;
                    184: 
                    185:   return find;
                    186: }
                    187: 
                    188: void
                    189: cluster_unintern (struct cluster_list *cluster)
                    190: {
                    191:   if (cluster->refcnt)
                    192:     cluster->refcnt--;
                    193: 
                    194:   if (cluster->refcnt == 0)
                    195:     {
1.1.1.2   misho     196:       hash_release (cluster_hash, cluster);
1.1       misho     197:       cluster_free (cluster);
                    198:     }
                    199: }
                    200: 
                    201: static void
                    202: cluster_init (void)
                    203: {
                    204:   cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
                    205: }
                    206: 
                    207: static void
                    208: cluster_finish (void)
                    209: {
1.1.1.4 ! misho     210:   hash_clean (cluster_hash, (void (*)(void *))cluster_free);
1.1       misho     211:   hash_free (cluster_hash);
                    212:   cluster_hash = NULL;
                    213: }
1.1.1.4 ! misho     214: 
        !           215: struct bgp_attr_encap_subtlv *
        !           216: encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
        !           217: {
        !           218:     struct bgp_attr_encap_subtlv *new;
        !           219:     struct bgp_attr_encap_subtlv *tail;
        !           220:     struct bgp_attr_encap_subtlv *p;
        !           221: 
        !           222:     for (p = orig, tail = new = NULL; p; p = p->next) {
        !           223:        int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length;
        !           224:        if (tail) {
        !           225:            tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
        !           226:            tail = tail->next;
        !           227:        } else {
        !           228:            tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
        !           229:        }
        !           230:        assert(tail);
        !           231:        memcpy(tail, p, size);
        !           232:        tail->next = NULL;
        !           233:     }
        !           234: 
        !           235:     return new;
        !           236: }
        !           237: 
        !           238: static void
        !           239: encap_free(struct bgp_attr_encap_subtlv *p)
        !           240: {
        !           241:     struct bgp_attr_encap_subtlv *next;
        !           242:     while (p) {
        !           243:         next    = p->next;
        !           244:         p->next = NULL;
        !           245:         XFREE(MTYPE_ENCAP_TLV, p);
        !           246:         p       = next;
        !           247:     }
        !           248: }
        !           249: 
        !           250: void
        !           251: bgp_attr_flush_encap(struct attr *attr)
        !           252: {
        !           253:     if (!attr || !attr->extra)
        !           254:        return;
        !           255: 
        !           256:     if (attr->extra->encap_subtlvs) {
        !           257:        encap_free(attr->extra->encap_subtlvs);
        !           258:        attr->extra->encap_subtlvs = NULL;
        !           259:     }
        !           260: }
        !           261: 
        !           262: /*
        !           263:  * Compare encap sub-tlv chains
        !           264:  *
        !           265:  *     1 = equivalent
        !           266:  *     0 = not equivalent
        !           267:  *
        !           268:  * This algorithm could be made faster if needed
        !           269:  */
        !           270: static int
        !           271: encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2)
        !           272: {
        !           273:     struct bgp_attr_encap_subtlv *p;
        !           274:     struct bgp_attr_encap_subtlv *q;
        !           275: 
        !           276:     if (!h1 && !h2)
        !           277:        return 1;
        !           278:     if (h1 && !h2)
        !           279:        return 0;
        !           280:     if (!h1 && h2)
        !           281:        return 0;
        !           282:     if (h1 == h2)
        !           283:        return 1;
        !           284: 
        !           285:     for (p = h1; p; p = p->next) {
        !           286:        for (q = h2; q; q = q->next) {
        !           287:            if ((p->type == q->type) &&
        !           288:                (p->length == q->length) &&
        !           289:                !memcmp(p->value, q->value, p->length)) {
        !           290: 
        !           291:                break;
        !           292:            }
        !           293:        }
        !           294:        if (!q)
        !           295:            return 0;
        !           296:     }
        !           297: 
        !           298:     for (p = h2; p; p = p->next) {
        !           299:        for (q = h1; q; q = q->next) {
        !           300:            if ((p->type == q->type) &&
        !           301:                (p->length == q->length) &&
        !           302:                !memcmp(p->value, q->value, p->length)) {
        !           303: 
        !           304:                break;
        !           305:            }
        !           306:        }
        !           307:        if (!q)
        !           308:            return 0;
        !           309:     }
        !           310: 
        !           311:     return 1;
        !           312: }
        !           313: 
1.1       misho     314: /* Unknown transit attribute. */
                    315: static struct hash *transit_hash;
                    316: 
                    317: static void
                    318: transit_free (struct transit *transit)
                    319: {
                    320:   if (transit->val)
                    321:     XFREE (MTYPE_TRANSIT_VAL, transit->val);
                    322:   XFREE (MTYPE_TRANSIT, transit);
                    323: }
                    324: 
                    325: 
                    326: static void *
                    327: transit_hash_alloc (void *p)
                    328: {
                    329:   /* Transit structure is already allocated.  */
                    330:   return p;
                    331: }
                    332: 
                    333: static struct transit *
                    334: transit_intern (struct transit *transit)
                    335: {
                    336:   struct transit *find;
                    337: 
                    338:   find = hash_get (transit_hash, transit, transit_hash_alloc);
                    339:   if (find != transit)
                    340:     transit_free (transit);
                    341:   find->refcnt++;
                    342: 
                    343:   return find;
                    344: }
                    345: 
                    346: void
                    347: transit_unintern (struct transit *transit)
                    348: {
                    349:   if (transit->refcnt)
                    350:     transit->refcnt--;
                    351: 
                    352:   if (transit->refcnt == 0)
                    353:     {
1.1.1.2   misho     354:       hash_release (transit_hash, transit);
1.1       misho     355:       transit_free (transit);
                    356:     }
                    357: }
                    358: 
                    359: static unsigned int
                    360: transit_hash_key_make (void *p)
                    361: {
                    362:   const struct transit * transit = p;
                    363: 
                    364:   return jhash(transit->val, transit->length, 0);
                    365: }
                    366: 
                    367: static int
                    368: transit_hash_cmp (const void *p1, const void *p2)
                    369: {
                    370:   const struct transit * transit1 = p1;
                    371:   const struct transit * transit2 = p2;
                    372: 
                    373:   return (transit1->length == transit2->length &&
                    374:          memcmp (transit1->val, transit2->val, transit1->length) == 0);
                    375: }
                    376: 
                    377: static void
                    378: transit_init (void)
                    379: {
                    380:   transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
                    381: }
                    382: 
                    383: static void
                    384: transit_finish (void)
                    385: {
1.1.1.4 ! misho     386:   hash_clean (transit_hash, (void (*)(void *))transit_free);
1.1       misho     387:   hash_free (transit_hash);
                    388:   transit_hash = NULL;
                    389: }
1.1.1.4 ! misho     390: 
1.1       misho     391: /* Attribute hash routines. */
                    392: static struct hash *attrhash;
                    393: 
                    394: static struct attr_extra *
                    395: bgp_attr_extra_new (void)
                    396: {
                    397:   return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
                    398: }
                    399: 
                    400: void
                    401: bgp_attr_extra_free (struct attr *attr)
                    402: {
                    403:   if (attr->extra)
                    404:     {
1.1.1.4 ! misho     405:       if (attr->extra->encap_subtlvs) {
        !           406:        encap_free(attr->extra->encap_subtlvs);
        !           407:        attr->extra->encap_subtlvs = NULL;
        !           408:       }
1.1       misho     409:       XFREE (MTYPE_ATTR_EXTRA, attr->extra);
                    410:       attr->extra = NULL;
                    411:     }
                    412: }
                    413: 
                    414: struct attr_extra *
                    415: bgp_attr_extra_get (struct attr *attr)
                    416: {
                    417:   if (!attr->extra)
                    418:     attr->extra = bgp_attr_extra_new();
                    419:   return attr->extra;
                    420: }
                    421: 
                    422: /* Shallow copy of an attribute
                    423:  * Though, not so shallow that it doesn't copy the contents
                    424:  * of the attr_extra pointed to by 'extra'
                    425:  */
                    426: void
                    427: bgp_attr_dup (struct attr *new, struct attr *orig)
                    428: {
1.1.1.3   misho     429:   struct attr_extra *extra = new->extra;
                    430: 
1.1       misho     431:   *new = *orig;
1.1.1.3   misho     432:   /* if caller provided attr_extra space, use it in any case.
                    433:    *
                    434:    * This is neccesary even if orig->extra equals NULL, because otherwise
                    435:    * memory may be later allocated on the heap by bgp_attr_extra_get.
                    436:    *
                    437:    * That memory would eventually be leaked, because the caller must not
                    438:    * call bgp_attr_extra_free if he provided attr_extra on the stack.
                    439:    */
                    440:   if (extra)
                    441:     {
                    442:       new->extra = extra;
                    443:       memset(new->extra, 0, sizeof(struct attr_extra));
1.1.1.4 ! misho     444:       if (orig->extra) {
1.1.1.3   misho     445:         *new->extra = *orig->extra;
1.1.1.4 ! misho     446:         if (orig->extra->encap_subtlvs) {
        !           447:           new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
        !           448:         }
        !           449:       }
1.1.1.3   misho     450:     }
                    451:   else if (orig->extra)
1.1       misho     452:     {
                    453:       new->extra = bgp_attr_extra_new();
                    454:       *new->extra = *orig->extra;
1.1.1.4 ! misho     455:       if (orig->extra->encap_subtlvs) {
        !           456:        new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
        !           457:       }
1.1       misho     458:     }
                    459: }
                    460: 
                    461: unsigned long int
                    462: attr_count (void)
                    463: {
                    464:   return attrhash->count;
                    465: }
                    466: 
                    467: unsigned long int
                    468: attr_unknown_count (void)
                    469: {
                    470:   return transit_hash->count;
                    471: }
                    472: 
                    473: unsigned int
                    474: attrhash_key_make (void *p)
                    475: {
1.1.1.3   misho     476:   const struct attr *attr = (struct attr *) p;
                    477:   const struct attr_extra *extra = attr->extra;
1.1       misho     478:   uint32_t key = 0;
                    479: #define MIX(val)       key = jhash_1word(val, key)
                    480: 
                    481:   MIX(attr->origin);
                    482:   MIX(attr->nexthop.s_addr);
                    483:   MIX(attr->med);
                    484:   MIX(attr->local_pref);
                    485: 
                    486:   key += attr->origin;
                    487:   key += attr->nexthop.s_addr;
                    488:   key += attr->med;
                    489:   key += attr->local_pref;
                    490:   
1.1.1.3   misho     491:   if (extra)
1.1       misho     492:     {
1.1.1.3   misho     493:       MIX(extra->aggregator_as);
                    494:       MIX(extra->aggregator_addr.s_addr);
                    495:       MIX(extra->weight);
                    496:       MIX(extra->mp_nexthop_global_in.s_addr);
1.1.1.4 ! misho     497:       MIX(extra->originator_id.s_addr);
1.1       misho     498:     }
                    499:   
                    500:   if (attr->aspath)
                    501:     MIX(aspath_key_make (attr->aspath));
                    502:   if (attr->community)
                    503:     MIX(community_hash_make (attr->community));
                    504:   
1.1.1.3   misho     505:   if (extra)
1.1       misho     506:     {
1.1.1.3   misho     507:       if (extra->ecommunity)
                    508:         MIX(ecommunity_hash_make (extra->ecommunity));
                    509:       if (extra->cluster)
                    510:         MIX(cluster_hash_key_make (extra->cluster));
                    511:       if (extra->transit)
                    512:         MIX(transit_hash_key_make (extra->transit));
1.1       misho     513: 
1.1.1.3   misho     514:       MIX(extra->mp_nexthop_len);
                    515:       key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
                    516:       key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
1.1       misho     517:     }
                    518: 
                    519:   return key;
                    520: }
                    521: 
                    522: int
                    523: attrhash_cmp (const void *p1, const void *p2)
                    524: {
                    525:   const struct attr * attr1 = p1;
                    526:   const struct attr * attr2 = p2;
                    527: 
                    528:   if (attr1->flag == attr2->flag
                    529:       && attr1->origin == attr2->origin
                    530:       && attr1->nexthop.s_addr == attr2->nexthop.s_addr
                    531:       && attr1->aspath == attr2->aspath
                    532:       && attr1->community == attr2->community
                    533:       && attr1->med == attr2->med
                    534:       && attr1->local_pref == attr2->local_pref)
                    535:     {
                    536:       const struct attr_extra *ae1 = attr1->extra;
                    537:       const struct attr_extra *ae2 = attr2->extra;
                    538:       
                    539:       if (ae1 && ae2
                    540:           && ae1->aggregator_as == ae2->aggregator_as
                    541:           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
                    542:           && ae1->weight == ae2->weight
                    543:           && ae1->mp_nexthop_len == ae2->mp_nexthop_len
                    544:           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
                    545:           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
                    546:           && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
                    547:           && ae1->ecommunity == ae2->ecommunity
                    548:           && ae1->cluster == ae2->cluster
1.1.1.4 ! misho     549:           && ae1->transit == ae2->transit
        !           550:          && (ae1->encap_tunneltype == ae2->encap_tunneltype)
        !           551:          && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs)
        !           552:           && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
1.1       misho     553:         return 1;
                    554:       else if (ae1 || ae2)
                    555:         return 0;
                    556:       /* neither attribute has extra attributes, so they're same */
                    557:       return 1;
                    558:     }
                    559:   else
                    560:     return 0;
                    561: }
                    562: 
                    563: static void
                    564: attrhash_init (void)
                    565: {
                    566:   attrhash = hash_create (attrhash_key_make, attrhash_cmp);
                    567: }
                    568: 
1.1.1.4 ! misho     569: /*
        !           570:  * special for hash_clean below
        !           571:  */
        !           572: static void
        !           573: attr_vfree (void *attr)
        !           574: {
        !           575:   bgp_attr_extra_free ((struct attr *)attr);
        !           576:   XFREE (MTYPE_ATTR, attr);
        !           577: }
        !           578: 
1.1       misho     579: static void
                    580: attrhash_finish (void)
                    581: {
1.1.1.4 ! misho     582:   hash_clean(attrhash, attr_vfree);
1.1       misho     583:   hash_free (attrhash);
                    584:   attrhash = NULL;
                    585: }
                    586: 
                    587: static void
                    588: attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
                    589: {
                    590:   struct attr *attr = backet->data;
                    591: 
                    592:   vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, 
                    593:           inet_ntoa (attr->nexthop), VTY_NEWLINE);
                    594: }
                    595: 
                    596: void
                    597: attr_show_all (struct vty *vty)
                    598: {
                    599:   hash_iterate (attrhash, 
                    600:                (void (*)(struct hash_backet *, void *))
                    601:                attr_show_all_iterator,
                    602:                vty);
                    603: }
                    604: 
                    605: static void *
                    606: bgp_attr_hash_alloc (void *p)
                    607: {
                    608:   struct attr * val = (struct attr *) p;
                    609:   struct attr *attr;
                    610: 
                    611:   attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
                    612:   *attr = *val;
                    613:   if (val->extra)
                    614:     {
                    615:       attr->extra = bgp_attr_extra_new ();
                    616:       *attr->extra = *val->extra;
1.1.1.4 ! misho     617: 
        !           618:       if (attr->extra->encap_subtlvs) {
        !           619:        attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs);
        !           620:       }
1.1       misho     621:     }
                    622:   attr->refcnt = 0;
                    623:   return attr;
                    624: }
                    625: 
                    626: /* Internet argument attribute. */
                    627: struct attr *
                    628: bgp_attr_intern (struct attr *attr)
                    629: {
                    630:   struct attr *find;
                    631: 
                    632:   /* Intern referenced strucutre. */
                    633:   if (attr->aspath)
                    634:     {
                    635:       if (! attr->aspath->refcnt)
                    636:        attr->aspath = aspath_intern (attr->aspath);
                    637:       else
                    638:        attr->aspath->refcnt++;
                    639:     }
                    640:   if (attr->community)
                    641:     {
                    642:       if (! attr->community->refcnt)
                    643:        attr->community = community_intern (attr->community);
                    644:       else
                    645:        attr->community->refcnt++;
                    646:     }
                    647:   if (attr->extra)
                    648:     {
                    649:       struct attr_extra *attre = attr->extra;
                    650:       
                    651:       if (attre->ecommunity)
                    652:         {
                    653:           if (! attre->ecommunity->refcnt)
                    654:             attre->ecommunity = ecommunity_intern (attre->ecommunity);
                    655:           else
                    656:             attre->ecommunity->refcnt++;
                    657:           
                    658:         }
                    659:       if (attre->cluster)
                    660:         {
                    661:           if (! attre->cluster->refcnt)
                    662:             attre->cluster = cluster_intern (attre->cluster);
                    663:           else
                    664:             attre->cluster->refcnt++;
                    665:         }
                    666:       if (attre->transit)
                    667:         {
                    668:           if (! attre->transit->refcnt)
                    669:             attre->transit = transit_intern (attre->transit);
                    670:           else
                    671:             attre->transit->refcnt++;
                    672:         }
                    673:     }
                    674:   
                    675:   find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
                    676:   find->refcnt++;
                    677:   
                    678:   return find;
                    679: }
                    680: 
                    681: 
                    682: /* Make network statement's attribute. */
                    683: struct attr *
                    684: bgp_attr_default_set (struct attr *attr, u_char origin)
                    685: {
                    686:   memset (attr, 0, sizeof (struct attr));
                    687:   bgp_attr_extra_get (attr);
                    688:   
                    689:   attr->origin = origin;
                    690:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
                    691:   attr->aspath = aspath_empty ();
                    692:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
                    693:   attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
                    694:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
                    695:   attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
                    696: 
                    697:   return attr;
                    698: }
                    699: 
                    700: 
                    701: /* Make network statement's attribute. */
                    702: struct attr *
                    703: bgp_attr_default_intern (u_char origin)
                    704: {
                    705:   struct attr attr;
                    706:   struct attr *new;
1.1.1.3   misho     707: 
1.1.1.4 ! misho     708:   memset (&attr, 0, sizeof (struct attr));
        !           709:   bgp_attr_extra_get (&attr);
        !           710: 
1.1       misho     711:   bgp_attr_default_set(&attr, origin);
                    712: 
                    713:   new = bgp_attr_intern (&attr);
                    714:   bgp_attr_extra_free (&attr);
                    715:   
                    716:   aspath_unintern (&new->aspath);
                    717:   return new;
                    718: }
                    719: 
                    720: struct attr *
                    721: bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
                    722:                           struct aspath *aspath,
                    723:                           struct community *community, int as_set)
                    724: {
                    725:   struct attr attr;
                    726:   struct attr *new;
1.1.1.3   misho     727:   struct attr_extra attre;
1.1       misho     728: 
                    729:   memset (&attr, 0, sizeof (struct attr));
1.1.1.3   misho     730:   memset (&attre, 0, sizeof (struct attr_extra));
                    731:   attr.extra = &attre;
                    732: 
1.1       misho     733:   /* Origin attribute. */
                    734:   attr.origin = origin;
                    735:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
                    736: 
                    737:   /* AS path attribute. */
                    738:   if (aspath)
                    739:     attr.aspath = aspath_intern (aspath);
                    740:   else
                    741:     attr.aspath = aspath_empty ();
                    742:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
                    743: 
                    744:   /* Next hop attribute.  */
                    745:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
                    746: 
                    747:   if (community)
                    748:     {
                    749:       attr.community = community;
                    750:       attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
                    751:     }
                    752: 
1.1.1.3   misho     753:   attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
                    754:   attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
1.1.1.4 ! misho     755: 
1.1       misho     756:   if (! as_set)
                    757:     attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
                    758:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
                    759:   if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
1.1.1.3   misho     760:     attre.aggregator_as = bgp->confed_id;
1.1       misho     761:   else
1.1.1.3   misho     762:     attre.aggregator_as = bgp->as;
                    763:   attre.aggregator_addr = bgp->router_id;
1.1       misho     764: 
                    765:   new = bgp_attr_intern (&attr);
1.1.1.3   misho     766: 
1.1       misho     767:   aspath_unintern (&new->aspath);
                    768:   return new;
                    769: }
                    770: 
                    771: /* Unintern just the sub-components of the attr, but not the attr */
                    772: void
                    773: bgp_attr_unintern_sub (struct attr *attr)
                    774: {
                    775:   /* aspath refcount shoud be decrement. */
                    776:   if (attr->aspath)
                    777:     aspath_unintern (&attr->aspath);
1.1.1.4 ! misho     778:   UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH));
1.1       misho     779:   
                    780:   if (attr->community)
                    781:     community_unintern (&attr->community);
1.1.1.4 ! misho     782:   UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
1.1       misho     783:   
                    784:   if (attr->extra)
                    785:     {
                    786:       if (attr->extra->ecommunity)
                    787:         ecommunity_unintern (&attr->extra->ecommunity);
1.1.1.4 ! misho     788:       UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
1.1       misho     789:       
                    790:       if (attr->extra->cluster)
                    791:         cluster_unintern (attr->extra->cluster);
1.1.1.4 ! misho     792:       UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
1.1       misho     793:       
                    794:       if (attr->extra->transit)
                    795:         transit_unintern (attr->extra->transit);
                    796:     }
                    797: }
                    798: 
                    799: /* Free bgp attribute and aspath. */
                    800: void
1.1.1.3   misho     801: bgp_attr_unintern (struct attr **pattr)
1.1       misho     802: {
1.1.1.3   misho     803:   struct attr *attr = *pattr;
1.1       misho     804:   struct attr *ret;
                    805:   struct attr tmp;
1.1.1.3   misho     806:   struct attr_extra tmp_extra;
1.1       misho     807:   
                    808:   /* Decrement attribute reference. */
1.1.1.3   misho     809:   attr->refcnt--;
1.1       misho     810:   
1.1.1.3   misho     811:   tmp = *attr;
1.1       misho     812:   
1.1.1.3   misho     813:   if (attr->extra)
1.1       misho     814:     {
1.1.1.3   misho     815:       tmp.extra = &tmp_extra;
                    816:       memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
1.1       misho     817:     }
                    818:   
                    819:   /* If reference becomes zero then free attribute object. */
1.1.1.3   misho     820:   if (attr->refcnt == 0)
                    821:     {
                    822:       ret = hash_release (attrhash, attr);
1.1       misho     823:       assert (ret != NULL);
1.1.1.3   misho     824:       bgp_attr_extra_free (attr);
                    825:       XFREE (MTYPE_ATTR, attr);
                    826:       *pattr = NULL;
1.1       misho     827:     }
                    828: 
                    829:   bgp_attr_unintern_sub (&tmp);
                    830: }
                    831: 
                    832: void
                    833: bgp_attr_flush (struct attr *attr)
                    834: {
                    835:   if (attr->aspath && ! attr->aspath->refcnt)
1.1.1.4 ! misho     836:     {
        !           837:       aspath_free (attr->aspath);
        !           838:       attr->aspath = NULL;
        !           839:     }
1.1       misho     840:   if (attr->community && ! attr->community->refcnt)
1.1.1.4 ! misho     841:     {
        !           842:       community_free (attr->community);
        !           843:       attr->community = NULL;
        !           844:     }
1.1       misho     845:   if (attr->extra)
                    846:     {
                    847:       struct attr_extra *attre = attr->extra;
                    848: 
                    849:       if (attre->ecommunity && ! attre->ecommunity->refcnt)
                    850:         ecommunity_free (&attre->ecommunity);
                    851:       if (attre->cluster && ! attre->cluster->refcnt)
1.1.1.4 ! misho     852:         {
        !           853:           cluster_free (attre->cluster);
        !           854:           attre->cluster = NULL;
        !           855:         }
1.1       misho     856:       if (attre->transit && ! attre->transit->refcnt)
1.1.1.4 ! misho     857:         {
        !           858:           transit_free (attre->transit);
        !           859:           attre->transit = NULL;
        !           860:         }
        !           861:       encap_free(attre->encap_subtlvs);
        !           862:       attre->encap_subtlvs = NULL;
1.1       misho     863:     }
                    864: }
                    865: 
                    866: /* Implement draft-scudder-idr-optional-transitive behaviour and
                    867:  * avoid resetting sessions for malformed attributes which are
                    868:  * are partial/optional and hence where the error likely was not
                    869:  * introduced by the sending neighbour.
                    870:  */
                    871: static bgp_attr_parse_ret_t
1.1.1.2   misho     872: bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
                    873:                     bgp_size_t length)
1.1       misho     874: {
1.1.1.2   misho     875:   struct peer *const peer = args->peer; 
                    876:   const u_int8_t flags = args->flags;
                    877:   /* startp and length must be special-cased, as whether or not to
                    878:    * send the attribute data with the NOTIFY depends on the error,
                    879:    * the caller therefore signals this with the seperate length argument
                    880:    */
                    881:   u_char *notify_datap = (length > 0 ? args->startp : NULL);
                    882:   
1.1       misho     883:   /* Only relax error handling for eBGP peers */
1.1.1.3   misho     884:   if (peer->sort != BGP_PEER_EBGP)
1.1       misho     885:     {
                    886:       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
1.1.1.2   misho     887:                                  notify_datap, length);
1.1       misho     888:       return BGP_ATTR_PARSE_ERROR;
                    889: 
                    890:     }
                    891:   
1.1.1.2   misho     892:   /* Adjust the stream getp to the end of the attribute, in case we can
                    893:    * still proceed but the caller hasn't read all the attribute.
                    894:    */
                    895:   stream_set_getp (BGP_INPUT (peer),
                    896:                    (args->startp - STREAM_DATA (BGP_INPUT (peer)))
                    897:                     + args->total);
                    898:   
                    899:   switch (args->type) {
                    900:     /* where an attribute is relatively inconsequential, e.g. it does not
                    901:      * affect route selection, and can be safely ignored, then any such
                    902:      * attributes which are malformed should just be ignored and the route
                    903:      * processed as normal.
1.1       misho     904:      */
                    905:     case BGP_ATTR_AS4_AGGREGATOR:
                    906:     case BGP_ATTR_AGGREGATOR:
                    907:     case BGP_ATTR_ATOMIC_AGGREGATE:
                    908:       return BGP_ATTR_PARSE_PROCEED;
                    909:     
                    910:     /* Core attributes, particularly ones which may influence route
1.1.1.2   misho     911:      * selection, should always cause session resets
1.1       misho     912:      */
                    913:     case BGP_ATTR_ORIGIN:
                    914:     case BGP_ATTR_AS_PATH:
                    915:     case BGP_ATTR_NEXT_HOP:
                    916:     case BGP_ATTR_MULTI_EXIT_DISC:
                    917:     case BGP_ATTR_LOCAL_PREF:
                    918:     case BGP_ATTR_COMMUNITIES:
                    919:     case BGP_ATTR_ORIGINATOR_ID:
                    920:     case BGP_ATTR_CLUSTER_LIST:
                    921:     case BGP_ATTR_MP_REACH_NLRI:
                    922:     case BGP_ATTR_MP_UNREACH_NLRI:
                    923:     case BGP_ATTR_EXT_COMMUNITIES:
                    924:       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
1.1.1.2   misho     925:                                  notify_datap, length);
1.1       misho     926:       return BGP_ATTR_PARSE_ERROR;
                    927:   }
                    928:   
                    929:   /* Partial optional attributes that are malformed should not cause
                    930:    * the whole session to be reset. Instead treat it as a withdrawal
                    931:    * of the routes, if possible.
                    932:    */
1.1.1.2   misho     933:   if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
                    934:       && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
                    935:       && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
1.1       misho     936:     return BGP_ATTR_PARSE_WITHDRAW;
                    937:   
                    938:   /* default to reset */
1.1.1.4 ! misho     939:   return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho     940: }
                    941: 
1.1.1.2   misho     942: /* Find out what is wrong with the path attribute flag bits and log the error.
                    943:    "Flag bits" here stand for Optional, Transitive and Partial, but not for
                    944:    Extended Length. Checking O/T/P bits at once implies, that the attribute
                    945:    being diagnosed is defined by RFC as either a "well-known" or an "optional,
                    946:    non-transitive" attribute. */
                    947: static void
                    948: bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
                    949:                          u_int8_t desired_flags /* how RFC says it must be */
                    950: )
                    951: {
                    952:   u_char seen = 0, i;
                    953:   u_char real_flags = args->flags;
                    954:   const u_int8_t attr_code = args->type;
                    955:   
                    956:   desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
                    957:   real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
                    958:   for (i = 0; i <= 2; i++) /* O,T,P, but not E */
                    959:     if
                    960:     (
                    961:       CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
                    962:       CHECK_FLAG (real_flags,    attr_flag_str[i].key)
                    963:     )
                    964:     {
                    965:       zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
                    966:             LOOKUP (attr_str, attr_code),
                    967:             CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
                    968:             attr_flag_str[i].str);
                    969:       seen = 1;
                    970:     }
                    971:   if (!seen)
                    972:     {
                    973:       zlog (args->peer->log, LOG_DEBUG,
                    974:             "Strange, %s called for attr %s, but no problem found with flags"
                    975:             " (real flags 0x%x, desired 0x%x)",
                    976:             __func__, LOOKUP (attr_str, attr_code),
                    977:             real_flags, desired_flags);
                    978:     }
                    979: }
                    980: 
                    981: /* Required flags for attributes. EXTLEN will be masked off when testing,
                    982:  * as will PARTIAL for optional+transitive attributes.
                    983:  */
                    984: const u_int8_t attr_flags_values [] = {
                    985:   [BGP_ATTR_ORIGIN] =           BGP_ATTR_FLAG_TRANS,
                    986:   [BGP_ATTR_AS_PATH] =          BGP_ATTR_FLAG_TRANS,
                    987:   [BGP_ATTR_NEXT_HOP] =         BGP_ATTR_FLAG_TRANS,
                    988:   [BGP_ATTR_MULTI_EXIT_DISC] =  BGP_ATTR_FLAG_OPTIONAL,
                    989:   [BGP_ATTR_LOCAL_PREF] =       BGP_ATTR_FLAG_TRANS,
                    990:   [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
                    991:   [BGP_ATTR_AGGREGATOR] =       BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
                    992:   [BGP_ATTR_COMMUNITIES] =      BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
                    993:   [BGP_ATTR_ORIGINATOR_ID] =    BGP_ATTR_FLAG_OPTIONAL,
                    994:   [BGP_ATTR_CLUSTER_LIST] =     BGP_ATTR_FLAG_OPTIONAL,
                    995:   [BGP_ATTR_MP_REACH_NLRI] =    BGP_ATTR_FLAG_OPTIONAL,
                    996:   [BGP_ATTR_MP_UNREACH_NLRI] =  BGP_ATTR_FLAG_OPTIONAL,
                    997:   [BGP_ATTR_EXT_COMMUNITIES] =  BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
                    998:   [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
                    999:   [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
                   1000: };
                   1001: static const size_t attr_flags_values_max =
                   1002:   sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
1.1       misho    1003: 
1.1.1.2   misho    1004: static int
                   1005: bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
                   1006: {
                   1007:   u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
                   1008:   const u_int8_t flags = args->flags;
                   1009:   const u_int8_t attr_code = args->type;
                   1010:   struct peer *const peer = args->peer; 
                   1011:   
                   1012:   /* there may be attributes we don't know about */
                   1013:   if (attr_code > attr_flags_values_max)
                   1014:     return 0;
                   1015:   if (attr_flags_values[attr_code] == 0)
                   1016:     return 0;
                   1017:   
                   1018:   /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
                   1019:    * 1."
                   1020:    */
                   1021:   if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
                   1022:       && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
1.1       misho    1023:     {
1.1.1.2   misho    1024:       zlog (peer->log, LOG_ERR,
                   1025:             "%s well-known attributes must have transitive flag set (%x)",
                   1026:             LOOKUP (attr_str, attr_code), flags);
                   1027:       return 1;
                   1028:     }
                   1029:   
                   1030:   /* "For well-known attributes and for optional non-transitive attributes,
                   1031:    *  the Partial bit MUST be set to 0." 
                   1032:    */
                   1033:   if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
                   1034:     {
                   1035:       if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
                   1036:         {
                   1037:           zlog (peer->log, LOG_ERR,
                   1038:                 "%s well-known attribute "
                   1039:                 "must NOT have the partial flag set (%x)",
                   1040:                  LOOKUP (attr_str, attr_code), flags);
                   1041:           return 1;
                   1042:         }
                   1043:       if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
                   1044:           && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
                   1045:         {
                   1046:           zlog (peer->log, LOG_ERR,
                   1047:                 "%s optional + transitive attribute "
                   1048:                 "must NOT have the partial flag set (%x)",
                   1049:                  LOOKUP (attr_str, attr_code), flags);
                   1050:           return 1;
                   1051:         }
1.1       misho    1052:     }
1.1.1.2   misho    1053:   
                   1054:   /* Optional transitive attributes may go through speakers that don't
                   1055:    * reocgnise them and set the Partial bit.
                   1056:    */
                   1057:   if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
                   1058:       && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
                   1059:     SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
                   1060:   
                   1061:   if ((flags & ~mask)
                   1062:       == attr_flags_values[attr_code])
                   1063:     return 0;
                   1064:   
                   1065:   bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
                   1066:   return 1;
                   1067: }
1.1       misho    1068: 
1.1.1.2   misho    1069: /* Get origin attribute of the update message. */
                   1070: static bgp_attr_parse_ret_t
                   1071: bgp_attr_origin (struct bgp_attr_parser_args *args)
                   1072: {
                   1073:   struct peer *const peer = args->peer;
                   1074:   struct attr *const attr = args->attr;
                   1075:   const bgp_size_t length = args->length;
                   1076:   
1.1       misho    1077:   /* If any recognized attribute has Attribute Length that conflicts
                   1078:      with the expected length (based on the attribute type code), then
                   1079:      the Error Subcode is set to Attribute Length Error.  The Data
                   1080:      field contains the erroneous attribute (type, length and
                   1081:      value). */
                   1082:   if (length != 1)
                   1083:     {
                   1084:       zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
                   1085:            length);
1.1.1.2   misho    1086:       return bgp_attr_malformed (args,
1.1       misho    1087:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1088:                                  args->total);
1.1       misho    1089:     }
                   1090: 
                   1091:   /* Fetch origin attribute. */
                   1092:   attr->origin = stream_getc (BGP_INPUT (peer));
                   1093: 
                   1094:   /* If the ORIGIN attribute has an undefined value, then the Error
                   1095:      Subcode is set to Invalid Origin Attribute.  The Data field
                   1096:      contains the unrecognized attribute (type, length and value). */
                   1097:   if ((attr->origin != BGP_ORIGIN_IGP)
                   1098:       && (attr->origin != BGP_ORIGIN_EGP)
                   1099:       && (attr->origin != BGP_ORIGIN_INCOMPLETE))
                   1100:     {
                   1101:       zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
                   1102:              attr->origin);
1.1.1.2   misho    1103:       return bgp_attr_malformed (args,
1.1       misho    1104:                                  BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
1.1.1.2   misho    1105:                                  args->total);
1.1       misho    1106:     }
                   1107: 
                   1108:   /* Set oring attribute flag. */
                   1109:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
                   1110: 
                   1111:   return 0;
                   1112: }
                   1113: 
                   1114: /* Parse AS path information.  This function is wrapper of
                   1115:    aspath_parse. */
                   1116: static int
1.1.1.2   misho    1117: bgp_attr_aspath (struct bgp_attr_parser_args *args)
1.1       misho    1118: {
1.1.1.2   misho    1119:   struct attr *const attr = args->attr;
                   1120:   struct peer *const peer = args->peer; 
                   1121:   const bgp_size_t length = args->length;
                   1122:   
1.1       misho    1123:   /*
                   1124:    * peer with AS4 => will get 4Byte ASnums
                   1125:    * otherwise, will get 16 Bit
                   1126:    */
                   1127:   attr->aspath = aspath_parse (peer->ibuf, length, 
                   1128:                                CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
                   1129: 
                   1130:   /* In case of IBGP, length will be zero. */
                   1131:   if (! attr->aspath)
                   1132:     {
                   1133:       zlog (peer->log, LOG_ERR,
                   1134:             "Malformed AS path from %s, length is %d",
                   1135:             peer->host, length);
1.1.1.2   misho    1136:       return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
1.1       misho    1137:     }
                   1138: 
                   1139:   /* Set aspath attribute flag. */
                   1140:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
                   1141: 
                   1142:   return BGP_ATTR_PARSE_PROCEED;
                   1143: }
                   1144: 
                   1145: static bgp_attr_parse_ret_t
1.1.1.2   misho    1146: bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
1.1       misho    1147: {
                   1148:   /* These checks were part of bgp_attr_aspath, but with
                   1149:    * as4 we should to check aspath things when
                   1150:    * aspath synthesizing with as4_path has already taken place.
                   1151:    * Otherwise we check ASPATH and use the synthesized thing, and that is
                   1152:    * not right.
                   1153:    * So do the checks later, i.e. here
                   1154:    */
                   1155:   struct bgp *bgp = peer->bgp;
                   1156:   struct aspath *aspath;
                   1157: 
                   1158:   /* Confederation sanity check. */
1.1.1.3   misho    1159:   if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
                   1160:      (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
1.1       misho    1161:     {
                   1162:       zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
1.1.1.2   misho    1163:       bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
                   1164:                        BGP_NOTIFY_UPDATE_MAL_AS_PATH);
                   1165:       return BGP_ATTR_PARSE_ERROR;
1.1       misho    1166:     }
                   1167: 
                   1168:   /* First AS check for EBGP. */
                   1169:   if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
                   1170:     {
1.1.1.3   misho    1171:       if (peer->sort == BGP_PEER_EBGP
1.1       misho    1172:          && ! aspath_firstas_check (attr->aspath, peer->as))
                   1173:        {
                   1174:          zlog (peer->log, LOG_ERR,
                   1175:                "%s incorrect first AS (must be %u)", peer->host, peer->as);
1.1.1.2   misho    1176:           bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
                   1177:                            BGP_NOTIFY_UPDATE_MAL_AS_PATH);
                   1178:           return BGP_ATTR_PARSE_ERROR;
1.1       misho    1179:        }
                   1180:     }
                   1181: 
                   1182:   /* local-as prepend */
                   1183:   if (peer->change_local_as &&
                   1184:       ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
                   1185:     {
                   1186:       aspath = aspath_dup (attr->aspath);
                   1187:       aspath = aspath_add_seq (aspath, peer->change_local_as);
                   1188:       aspath_unintern (&attr->aspath);
                   1189:       attr->aspath = aspath_intern (aspath);
                   1190:     }
                   1191: 
                   1192:   return BGP_ATTR_PARSE_PROCEED;
                   1193: }
                   1194: 
                   1195: /* Parse AS4 path information.  This function is another wrapper of
                   1196:    aspath_parse. */
                   1197: static int
1.1.1.2   misho    1198: bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
1.1       misho    1199: {
1.1.1.2   misho    1200:   struct peer *const peer = args->peer; 
                   1201:   struct attr *const attr = args->attr;
                   1202:   const bgp_size_t length = args->length;
                   1203:   
1.1       misho    1204:   *as4_path = aspath_parse (peer->ibuf, length, 1);
                   1205: 
                   1206:   /* In case of IBGP, length will be zero. */
                   1207:   if (!*as4_path)
                   1208:     {
                   1209:       zlog (peer->log, LOG_ERR,
                   1210:             "Malformed AS4 path from %s, length is %d",
                   1211:             peer->host, length);
1.1.1.2   misho    1212:       return bgp_attr_malformed (args,
1.1       misho    1213:                                  BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1.1.1.2   misho    1214:                                  0);
1.1       misho    1215:     }
                   1216: 
                   1217:   /* Set aspath attribute flag. */
                   1218:   if (as4_path)
                   1219:     attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
                   1220: 
                   1221:   return BGP_ATTR_PARSE_PROCEED;
                   1222: }
                   1223: 
                   1224: /* Nexthop attribute. */
                   1225: static bgp_attr_parse_ret_t
1.1.1.2   misho    1226: bgp_attr_nexthop (struct bgp_attr_parser_args *args)
1.1       misho    1227: {
1.1.1.2   misho    1228:   struct peer *const peer = args->peer; 
                   1229:   struct attr *const attr = args->attr;
                   1230:   const bgp_size_t length = args->length;
                   1231:   
                   1232:   in_addr_t nexthop_h, nexthop_n;
1.1       misho    1233: 
                   1234:   /* Check nexthop attribute length. */
                   1235:   if (length != 4)
                   1236:     {
                   1237:       zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
                   1238:              length);
                   1239: 
1.1.1.2   misho    1240:       return bgp_attr_malformed (args,
1.1       misho    1241:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1242:                                  args->total);
1.1       misho    1243:     }
                   1244: 
1.1.1.2   misho    1245:   /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
                   1246:      attribute must result in a NOTIFICATION message (this is implemented below).
                   1247:      At the same time, semantically incorrect NEXT_HOP is more likely to be just
                   1248:      logged locally (this is implemented somewhere else). The UPDATE message
                   1249:      gets ignored in any of these cases. */
                   1250:   nexthop_n = stream_get_ipv4 (peer->ibuf);
                   1251:   nexthop_h = ntohl (nexthop_n);
                   1252:   if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
                   1253:     {
                   1254:       char buf[INET_ADDRSTRLEN];
1.1.1.4 ! misho    1255:       inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
1.1.1.2   misho    1256:       zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
                   1257:       return bgp_attr_malformed (args,
                   1258:                                  BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
                   1259:                                  args->total);
                   1260:     }
                   1261: 
                   1262:   attr->nexthop.s_addr = nexthop_n;
1.1       misho    1263:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
                   1264: 
                   1265:   return BGP_ATTR_PARSE_PROCEED;
                   1266: }
                   1267: 
                   1268: /* MED atrribute. */
                   1269: static bgp_attr_parse_ret_t
1.1.1.2   misho    1270: bgp_attr_med (struct bgp_attr_parser_args *args)
1.1       misho    1271: {
1.1.1.2   misho    1272:   struct peer *const peer = args->peer; 
                   1273:   struct attr *const attr = args->attr;
                   1274:   const bgp_size_t length = args->length;
                   1275:   
1.1       misho    1276:   /* Length check. */
                   1277:   if (length != 4)
                   1278:     {
                   1279:       zlog (peer->log, LOG_ERR, 
                   1280:            "MED attribute length isn't four [%d]", length);
                   1281: 
1.1.1.2   misho    1282:       return bgp_attr_malformed (args,
1.1       misho    1283:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1284:                                  args->total);
1.1       misho    1285:     }
                   1286: 
                   1287:   attr->med = stream_getl (peer->ibuf);
                   1288: 
                   1289:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
                   1290: 
                   1291:   return BGP_ATTR_PARSE_PROCEED;
                   1292: }
                   1293: 
                   1294: /* Local preference attribute. */
                   1295: static bgp_attr_parse_ret_t
1.1.1.2   misho    1296: bgp_attr_local_pref (struct bgp_attr_parser_args *args)
1.1       misho    1297: {
1.1.1.2   misho    1298:   struct peer *const peer = args->peer; 
                   1299:   struct attr *const attr = args->attr;
                   1300:   const bgp_size_t length = args->length;
                   1301:   
                   1302:   /* Length check. */
                   1303:   if (length != 4)
                   1304:   {
                   1305:     zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
                   1306:           length);
                   1307:     return bgp_attr_malformed (args,
                   1308:                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                   1309:                                args->total);
                   1310:   }
1.1       misho    1311: 
                   1312:   /* If it is contained in an UPDATE message that is received from an
                   1313:      external peer, then this attribute MUST be ignored by the
                   1314:      receiving speaker. */
1.1.1.3   misho    1315:   if (peer->sort == BGP_PEER_EBGP)
1.1       misho    1316:     {
                   1317:       stream_forward_getp (peer->ibuf, length);
                   1318:       return BGP_ATTR_PARSE_PROCEED;
                   1319:     }
                   1320: 
1.1.1.2   misho    1321:   attr->local_pref = stream_getl (peer->ibuf);
1.1       misho    1322: 
                   1323:   /* Set atomic aggregate flag. */
                   1324:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
                   1325: 
                   1326:   return BGP_ATTR_PARSE_PROCEED;
                   1327: }
                   1328: 
                   1329: /* Atomic aggregate. */
                   1330: static int
1.1.1.2   misho    1331: bgp_attr_atomic (struct bgp_attr_parser_args *args)
1.1       misho    1332: {
1.1.1.2   misho    1333:   struct peer *const peer = args->peer; 
                   1334:   struct attr *const attr = args->attr;
                   1335:   const bgp_size_t length = args->length;
                   1336:   
1.1       misho    1337:   /* Length check. */
                   1338:   if (length != 0)
                   1339:     {
1.1.1.2   misho    1340:       zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
                   1341:             length);
                   1342:       return bgp_attr_malformed (args,
1.1       misho    1343:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1344:                                  args->total);
1.1       misho    1345:     }
                   1346: 
                   1347:   /* Set atomic aggregate flag. */
                   1348:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
                   1349: 
                   1350:   return BGP_ATTR_PARSE_PROCEED;
                   1351: }
                   1352: 
                   1353: /* Aggregator attribute */
                   1354: static int
1.1.1.2   misho    1355: bgp_attr_aggregator (struct bgp_attr_parser_args *args)
1.1       misho    1356: {
1.1.1.2   misho    1357:   struct peer *const peer = args->peer; 
                   1358:   struct attr *const attr = args->attr;
                   1359:   const bgp_size_t length = args->length;
                   1360:   
1.1       misho    1361:   int wantedlen = 6;
                   1362:   struct attr_extra *attre = bgp_attr_extra_get (attr);
                   1363:   
                   1364:   /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
                   1365:   if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
                   1366:     wantedlen = 8;
                   1367:   
                   1368:   if (length != wantedlen)
                   1369:     {
1.1.1.2   misho    1370:       zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
                   1371:             wantedlen, length);
                   1372:       return bgp_attr_malformed (args,
1.1       misho    1373:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1374:                                  args->total);
1.1       misho    1375:     }
                   1376:   
                   1377:   if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
                   1378:     attre->aggregator_as = stream_getl (peer->ibuf);
                   1379:   else
                   1380:     attre->aggregator_as = stream_getw (peer->ibuf);
                   1381:   attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
                   1382: 
                   1383:   /* Set atomic aggregate flag. */
                   1384:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
                   1385: 
                   1386:   return BGP_ATTR_PARSE_PROCEED;
                   1387: }
                   1388: 
                   1389: /* New Aggregator attribute */
                   1390: static bgp_attr_parse_ret_t
1.1.1.2   misho    1391: bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
                   1392:                         as_t *as4_aggregator_as,
                   1393:                         struct in_addr *as4_aggregator_addr)
                   1394: {
                   1395:   struct peer *const peer = args->peer; 
                   1396:   struct attr *const attr = args->attr;
                   1397:   const bgp_size_t length = args->length;
                   1398:       
1.1       misho    1399:   if (length != 8)
                   1400:     {
1.1.1.2   misho    1401:       zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
                   1402:             length);
                   1403:       return bgp_attr_malformed (args,
1.1       misho    1404:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1405:                                  0);
1.1       misho    1406:     }
1.1.1.2   misho    1407:   
1.1       misho    1408:   *as4_aggregator_as = stream_getl (peer->ibuf);
                   1409:   as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
                   1410: 
                   1411:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
                   1412: 
                   1413:   return BGP_ATTR_PARSE_PROCEED;
                   1414: }
                   1415: 
                   1416: /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
                   1417:  */
                   1418: static bgp_attr_parse_ret_t
1.1.1.2   misho    1419: bgp_attr_munge_as4_attrs (struct peer *const peer,
                   1420:                           struct attr *const attr,
1.1       misho    1421:                           struct aspath *as4_path, as_t as4_aggregator,
                   1422:                           struct in_addr *as4_aggregator_addr)
                   1423: {
                   1424:   int ignore_as4_path = 0;
                   1425:   struct aspath *newpath;
                   1426:   struct attr_extra *attre = attr->extra;
1.1.1.4 ! misho    1427:   
        !          1428:   if (!attr->aspath)
        !          1429:     {
        !          1430:       /* NULL aspath shouldn't be possible as bgp_attr_parse should have
        !          1431:        * checked that all well-known, mandatory attributes were present.
        !          1432:        * 
        !          1433:        * Can only be a problem with peer itself - hard error
        !          1434:        */
        !          1435:       return BGP_ATTR_PARSE_ERROR;
        !          1436:     }
        !          1437:   
1.1       misho    1438:   if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
                   1439:     {
                   1440:       /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
                   1441:        * if given.
                   1442:        * It is worth a warning though, because the peer really
                   1443:        * should not send them
                   1444:        */
                   1445:       if (BGP_DEBUG(as4, AS4))
                   1446:         {
                   1447:           if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
                   1448:             zlog_debug ("[AS4] %s %s AS4_PATH",
                   1449:                         peer->host, "AS4 capable peer, yet it sent");
                   1450:           
                   1451:           if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
                   1452:             zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
                   1453:                         peer->host, "AS4 capable peer, yet it sent");
                   1454:         }
                   1455:       
                   1456:       return BGP_ATTR_PARSE_PROCEED;
                   1457:     }
                   1458:   
                   1459:   /* We have a asn16 peer.  First, look for AS4_AGGREGATOR
                   1460:    * because that may override AS4_PATH
                   1461:    */
                   1462:   if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
                   1463:     {
                   1464:       if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
                   1465:         {
                   1466:           assert (attre);
                   1467:           
                   1468:           /* received both.
                   1469:            * if the as_number in aggregator is not AS_TRANS,
                   1470:            *  then AS4_AGGREGATOR and AS4_PATH shall be ignored
                   1471:            *        and the Aggregator shall be taken as 
                   1472:            *        info on the aggregating node, and the AS_PATH
                   1473:            *        shall be taken as the AS_PATH
                   1474:            *  otherwise
                   1475:            *        the Aggregator shall be ignored and the
                   1476:            *        AS4_AGGREGATOR shall be taken as the
                   1477:            *        Aggregating node and the AS_PATH is to be
                   1478:            *        constructed "as in all other cases"
                   1479:            */
                   1480:           if (attre->aggregator_as != BGP_AS_TRANS)
                   1481:             {
                   1482:               /* ignore */
                   1483:               if ( BGP_DEBUG(as4, AS4))
                   1484:                 zlog_debug ("[AS4] %s BGP not AS4 capable peer" 
                   1485:                             " send AGGREGATOR != AS_TRANS and"
                   1486:                             " AS4_AGGREGATOR, so ignore"
                   1487:                             " AS4_AGGREGATOR and AS4_PATH", peer->host);
                   1488:               ignore_as4_path = 1;
                   1489:             }
                   1490:           else
                   1491:             {
                   1492:               /* "New_aggregator shall be taken as aggregator" */
                   1493:               attre->aggregator_as = as4_aggregator;
                   1494:               attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
                   1495:             }
                   1496:         }
                   1497:       else
                   1498:         {
                   1499:           /* We received a AS4_AGGREGATOR but no AGGREGATOR.
                   1500:            * That is bogus - but reading the conditions
                   1501:            * we have to handle AS4_AGGREGATOR as if it were
                   1502:            * AGGREGATOR in that case
                   1503:            */
                   1504:           if ( BGP_DEBUG(as4, AS4))
                   1505:             zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
                   1506:                         " AS4_AGGREGATOR but no AGGREGATOR, will take"
                   1507:                         " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
                   1508:           (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
                   1509:           /* sweep it under the carpet and simulate a "good" AGGREGATOR */
                   1510:           attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
                   1511:         }
                   1512:     }
                   1513: 
                   1514:   /* need to reconcile NEW_AS_PATH and AS_PATH */
                   1515:   if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
                   1516:     {
1.1.1.4 ! misho    1517:       newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
        !          1518:       aspath_unintern (&attr->aspath);
        !          1519:       attr->aspath = aspath_intern (newpath);
1.1       misho    1520:     }
                   1521:   return BGP_ATTR_PARSE_PROCEED;
                   1522: }
                   1523: 
                   1524: /* Community attribute. */
                   1525: static bgp_attr_parse_ret_t
1.1.1.2   misho    1526: bgp_attr_community (struct bgp_attr_parser_args *args)
1.1       misho    1527: {
1.1.1.2   misho    1528:   struct peer *const peer = args->peer; 
                   1529:   struct attr *const attr = args->attr;  
                   1530:   const bgp_size_t length = args->length;
1.1       misho    1531:   
                   1532:   if (length == 0)
                   1533:     {
                   1534:       attr->community = NULL;
                   1535:       return BGP_ATTR_PARSE_PROCEED;
                   1536:     }
                   1537:   
                   1538:   attr->community =
                   1539:     community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
                   1540:   
                   1541:   /* XXX: fix community_parse to use stream API and remove this */
                   1542:   stream_forward_getp (peer->ibuf, length);
                   1543: 
                   1544:   if (!attr->community)
1.1.1.2   misho    1545:     return bgp_attr_malformed (args,
1.1       misho    1546:                                BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1.1.1.2   misho    1547:                                args->total);
1.1       misho    1548:   
                   1549:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
                   1550: 
                   1551:   return BGP_ATTR_PARSE_PROCEED;
                   1552: }
                   1553: 
                   1554: /* Originator ID attribute. */
                   1555: static bgp_attr_parse_ret_t
1.1.1.2   misho    1556: bgp_attr_originator_id (struct bgp_attr_parser_args *args)
1.1       misho    1557: {
1.1.1.2   misho    1558:   struct peer *const peer = args->peer; 
                   1559:   struct attr *const attr = args->attr;
                   1560:   const bgp_size_t length = args->length;
                   1561:   
                   1562:   /* Length check. */
1.1       misho    1563:   if (length != 4)
                   1564:     {
                   1565:       zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
                   1566: 
1.1.1.2   misho    1567:       return bgp_attr_malformed (args,
1.1       misho    1568:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2   misho    1569:                                  args->total);
1.1       misho    1570:     }
                   1571: 
                   1572:   (bgp_attr_extra_get (attr))->originator_id.s_addr 
                   1573:     = stream_get_ipv4 (peer->ibuf);
                   1574: 
                   1575:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
                   1576: 
                   1577:   return BGP_ATTR_PARSE_PROCEED;
                   1578: }
                   1579: 
                   1580: /* Cluster list attribute. */
                   1581: static bgp_attr_parse_ret_t
1.1.1.2   misho    1582: bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
1.1       misho    1583: {
1.1.1.2   misho    1584:   struct peer *const peer = args->peer; 
                   1585:   struct attr *const attr = args->attr;
                   1586:   const bgp_size_t length = args->length;
                   1587:   
1.1       misho    1588:   /* Check length. */
                   1589:   if (length % 4)
                   1590:     {
                   1591:       zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
                   1592: 
1.1.1.2   misho    1593:       return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                   1594:                                  args->total);
1.1       misho    1595:     }
                   1596: 
                   1597:   (bgp_attr_extra_get (attr))->cluster 
                   1598:     = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
                   1599:   
                   1600:   /* XXX: Fix cluster_parse to use stream API and then remove this */
                   1601:   stream_forward_getp (peer->ibuf, length);
                   1602: 
                   1603:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
                   1604: 
                   1605:   return BGP_ATTR_PARSE_PROCEED;
                   1606: }
                   1607: 
                   1608: /* Multiprotocol reachability information parse. */
                   1609: int
1.1.1.2   misho    1610: bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
                   1611:                     struct bgp_nlri *mp_update)
1.1       misho    1612: {
                   1613:   afi_t afi;
                   1614:   safi_t safi;
                   1615:   bgp_size_t nlri_len;
                   1616:   size_t start;
                   1617:   struct stream *s;
1.1.1.2   misho    1618:   struct peer *const peer = args->peer;  
                   1619:   struct attr *const attr = args->attr;
                   1620:   const bgp_size_t length = args->length;
1.1       misho    1621:   struct attr_extra *attre = bgp_attr_extra_get(attr);
                   1622:   
                   1623:   /* Set end of packet. */
                   1624:   s = BGP_INPUT(peer);
                   1625:   start = stream_get_getp(s);
                   1626:   
                   1627:   /* safe to read statically sized header? */
                   1628: #define BGP_MP_REACH_MIN_SIZE 5
                   1629: #define LEN_LEFT       (length - (stream_get_getp(s) - start))
                   1630:   if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
                   1631:     {
                   1632:       zlog_info ("%s: %s sent invalid length, %lu", 
                   1633:                 __func__, peer->host, (unsigned long)length);
1.1.1.4 ! misho    1634:       return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho    1635:     }
                   1636:   
                   1637:   /* Load AFI, SAFI. */
                   1638:   afi = stream_getw (s);
                   1639:   safi = stream_getc (s);
                   1640: 
                   1641:   /* Get nexthop length. */
                   1642:   attre->mp_nexthop_len = stream_getc (s);
                   1643:   
                   1644:   if (LEN_LEFT < attre->mp_nexthop_len)
                   1645:     {
                   1646:       zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", 
                   1647:                 __func__, peer->host, attre->mp_nexthop_len);
1.1.1.4 ! misho    1648:       return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho    1649:     }
                   1650:   
                   1651:   /* Nexthop length check. */
                   1652:   switch (attre->mp_nexthop_len)
                   1653:     {
                   1654:     case 4:
                   1655:       stream_get (&attre->mp_nexthop_global_in, s, 4);
                   1656:       /* Probably needed for RFC 2283 */
                   1657:       if (attr->nexthop.s_addr == 0)
                   1658:         memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
                   1659:       break;
                   1660:     case 12:
1.1.1.2   misho    1661:       stream_getl (s); /* RD high */
                   1662:       stream_getl (s); /* RD low */
                   1663:       stream_get (&attre->mp_nexthop_global_in, s, 4);
1.1       misho    1664:       break;
1.1.1.4 ! misho    1665:     case 24:
        !          1666:       {
        !          1667:         u_int32_t rd_high __attribute__((unused));
        !          1668:         u_int32_t rd_low __attribute__((unused));
        !          1669: 
        !          1670:         rd_high = stream_getl (s);
        !          1671:         rd_low = stream_getl (s);
        !          1672:       }
        !          1673:       /* fall through */
1.1       misho    1674:     case 16:
                   1675:       stream_get (&attre->mp_nexthop_global, s, 16);
                   1676:       break;
                   1677:     case 32:
1.1.1.4 ! misho    1678:     case 48:
        !          1679:       if (attre->mp_nexthop_len == 48) {
        !          1680:         u_int32_t rd_high __attribute__((unused));
        !          1681:         u_int32_t rd_low __attribute__((unused));
        !          1682: 
        !          1683:         rd_high = stream_getl (s);
        !          1684:         rd_low = stream_getl (s);
        !          1685:       }
1.1       misho    1686:       stream_get (&attre->mp_nexthop_global, s, 16);
1.1.1.4 ! misho    1687: 
        !          1688:       if (attre->mp_nexthop_len == 48) {
        !          1689:         u_int32_t rd_high __attribute__((unused));
        !          1690:         u_int32_t rd_low __attribute__((unused));
        !          1691: 
        !          1692:         rd_high = stream_getl (s);
        !          1693:         rd_low = stream_getl (s);
        !          1694:       }
1.1       misho    1695:       stream_get (&attre->mp_nexthop_local, s, 16);
                   1696:       if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
                   1697:        {
                   1698:          char buf1[INET6_ADDRSTRLEN];
                   1699:          char buf2[INET6_ADDRSTRLEN];
                   1700: 
                   1701:          if (BGP_DEBUG (update, UPDATE_IN))
                   1702:            zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
                   1703:                       inet_ntop (AF_INET6, &attre->mp_nexthop_global,
                   1704:                                  buf1, INET6_ADDRSTRLEN),
                   1705:                       inet_ntop (AF_INET6, &attre->mp_nexthop_local,
                   1706:                                  buf2, INET6_ADDRSTRLEN));
                   1707: 
                   1708:          attre->mp_nexthop_len = 16;
                   1709:        }
                   1710:       break;
                   1711:     default:
                   1712:       zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", 
                   1713:                 __func__, peer->host, attre->mp_nexthop_len);
1.1.1.4 ! misho    1714:       return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho    1715:     }
                   1716: 
                   1717:   if (!LEN_LEFT)
                   1718:     {
                   1719:       zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
                   1720:                  __func__, peer->host);
1.1.1.4 ! misho    1721:       return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho    1722:     }
                   1723:   
                   1724:   {
                   1725:     u_char val; 
                   1726:     if ((val = stream_getc (s)))
                   1727:     zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
                   1728:                 peer->host, val);
                   1729:   }
                   1730:   
                   1731:   /* must have nrli_len, what is left of the attribute */
                   1732:   nlri_len = LEN_LEFT;
                   1733:   if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
                   1734:     {
                   1735:       zlog_info ("%s: (%s) Failed to read NLRI",
                   1736:                  __func__, peer->host);
1.1.1.4 ! misho    1737:       return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho    1738:     }
1.1.1.4 ! misho    1739:   
1.1       misho    1740:   mp_update->afi = afi;
                   1741:   mp_update->safi = safi;
                   1742:   mp_update->nlri = stream_pnt (s);
                   1743:   mp_update->length = nlri_len;
                   1744: 
                   1745:   stream_forward_getp (s, nlri_len);
                   1746: 
1.1.1.4 ! misho    1747:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI);
        !          1748: 
1.1       misho    1749:   return BGP_ATTR_PARSE_PROCEED;
                   1750: #undef LEN_LEFT
                   1751: }
                   1752: 
                   1753: /* Multiprotocol unreachable parse */
                   1754: int
1.1.1.2   misho    1755: bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
1.1       misho    1756:                      struct bgp_nlri *mp_withdraw)
                   1757: {
                   1758:   struct stream *s;
                   1759:   afi_t afi;
                   1760:   safi_t safi;
                   1761:   u_int16_t withdraw_len;
1.1.1.2   misho    1762:   struct peer *const peer = args->peer;  
1.1.1.4 ! misho    1763:   struct attr *const attr = args->attr;
1.1.1.2   misho    1764:   const bgp_size_t length = args->length;
1.1       misho    1765: 
                   1766:   s = peer->ibuf;
                   1767:   
                   1768: #define BGP_MP_UNREACH_MIN_SIZE 3
                   1769:   if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE))
1.1.1.4 ! misho    1770:     return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1.1       misho    1771:   
                   1772:   afi = stream_getw (s);
                   1773:   safi = stream_getc (s);
                   1774:   
                   1775:   withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
                   1776: 
                   1777:   mp_withdraw->afi = afi;
                   1778:   mp_withdraw->safi = safi;
                   1779:   mp_withdraw->nlri = stream_pnt (s);
                   1780:   mp_withdraw->length = withdraw_len;
                   1781: 
                   1782:   stream_forward_getp (s, withdraw_len);
                   1783: 
1.1.1.4 ! misho    1784:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI);
        !          1785: 
1.1       misho    1786:   return BGP_ATTR_PARSE_PROCEED;
                   1787: }
                   1788: 
                   1789: /* Extended Community attribute. */
                   1790: static bgp_attr_parse_ret_t
1.1.1.2   misho    1791: bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
1.1       misho    1792: {
1.1.1.2   misho    1793:   struct peer *const peer = args->peer;  
                   1794:   struct attr *const attr = args->attr;  
                   1795:   const bgp_size_t length = args->length;
1.1       misho    1796:   
                   1797:   if (length == 0)
                   1798:     {
                   1799:       if (attr->extra)
                   1800:         attr->extra->ecommunity = NULL;
                   1801:       /* Empty extcomm doesn't seem to be invalid per se */
                   1802:       return BGP_ATTR_PARSE_PROCEED;
                   1803:     }
                   1804: 
                   1805:   (bgp_attr_extra_get (attr))->ecommunity =
                   1806:     ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
                   1807:   /* XXX: fix ecommunity_parse to use stream API */
                   1808:   stream_forward_getp (peer->ibuf, length);
                   1809:   
                   1810:   if (!attr->extra->ecommunity)
1.1.1.2   misho    1811:     return bgp_attr_malformed (args,
                   1812:                                BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                   1813:                                args->total);
1.1       misho    1814:   
                   1815:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
                   1816: 
                   1817:   return BGP_ATTR_PARSE_PROCEED;
                   1818: }
                   1819: 
1.1.1.4 ! misho    1820: /* Parse Tunnel Encap attribute in an UPDATE */
        !          1821: static int
        !          1822: bgp_attr_encap(
        !          1823:   uint8_t      type,
        !          1824:   struct peer  *peer,  /* IN */
        !          1825:   bgp_size_t   length, /* IN: attr's length field */
        !          1826:   struct attr  *attr,  /* IN: caller already allocated */
        !          1827:   u_char       flag,   /* IN: attr's flags field */
        !          1828:   u_char       *startp)
        !          1829: {
        !          1830:   bgp_size_t                   total;
        !          1831:   struct attr_extra            *attre = NULL;
        !          1832:   struct bgp_attr_encap_subtlv *stlv_last = NULL;
        !          1833:   uint16_t                     tunneltype;
        !          1834: 
        !          1835:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1836: 
        !          1837:   if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
        !          1838:        || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
        !          1839:     {
        !          1840:       zlog (peer->log, LOG_ERR,
        !          1841:            "Tunnel Encap attribute flag isn't optional and transitive %d", flag);
        !          1842:       bgp_notify_send_with_data (peer,
        !          1843:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1844:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1845:                                 startp, total);
        !          1846:       return -1;
        !          1847:     }
        !          1848: 
        !          1849:   if (BGP_ATTR_ENCAP == type) {
        !          1850:     /* read outer TLV type and length */
        !          1851:     uint16_t   tlv_length;
        !          1852: 
        !          1853:     if (length < 4) {
        !          1854:        zlog (peer->log, LOG_ERR,
        !          1855:            "Tunnel Encap attribute not long enough to contain outer T,L");
        !          1856:        bgp_notify_send_with_data(peer,
        !          1857:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1858:                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
        !          1859:                                 startp, total);
        !          1860:        return -1;
        !          1861:     }
        !          1862:     tunneltype = stream_getw (BGP_INPUT (peer));
        !          1863:     tlv_length = stream_getw (BGP_INPUT (peer));
        !          1864:     length -= 4;
        !          1865: 
        !          1866:     if (tlv_length != length) {
        !          1867:        zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)",
        !          1868:            __func__, tlv_length, length);
        !          1869:     }
        !          1870:   }
        !          1871: 
        !          1872:   while (length >= 4) {
        !          1873:     uint16_t   subtype;
        !          1874:     uint16_t   sublength;
        !          1875:     struct bgp_attr_encap_subtlv *tlv;
        !          1876: 
        !          1877:     if (BGP_ATTR_ENCAP == type) {
        !          1878:         subtype   = stream_getc (BGP_INPUT (peer));
        !          1879:         sublength = stream_getc (BGP_INPUT (peer));
        !          1880:         length   -= 2;
        !          1881:     }
        !          1882: 
        !          1883:     if (sublength > length) {
        !          1884:       zlog (peer->log, LOG_ERR,
        !          1885:            "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
        !          1886:            sublength, length);
        !          1887:       bgp_notify_send_with_data (peer,
        !          1888:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1889:                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
        !          1890:                                 startp, total);
        !          1891:       return -1;
        !          1892:     }
        !          1893: 
        !          1894:     /* alloc and copy sub-tlv */
        !          1895:     /* TBD make sure these are freed when attributes are released */
        !          1896:     tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength);
        !          1897:     tlv->type = subtype;
        !          1898:     tlv->length = sublength;
        !          1899:     stream_get(tlv->value, peer->ibuf, sublength);
        !          1900:     length -= sublength;
        !          1901: 
        !          1902:     /* attach tlv to encap chain */
        !          1903:     if (!attre) {
        !          1904:        attre = bgp_attr_extra_get(attr);
        !          1905:        if (BGP_ATTR_ENCAP == type) {
        !          1906:            for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next;
        !          1907:                stlv_last = stlv_last->next);
        !          1908:            if (stlv_last) {
        !          1909:                stlv_last->next = tlv;
        !          1910:            } else {
        !          1911:                attre->encap_subtlvs = tlv;
        !          1912:            }
        !          1913:        }
        !          1914:     } else {
        !          1915:        stlv_last->next = tlv;
        !          1916:     }
        !          1917:     stlv_last = tlv;
        !          1918:   }
        !          1919: 
        !          1920:   if (attre && (BGP_ATTR_ENCAP == type)) {
        !          1921:       attre->encap_tunneltype = tunneltype;
        !          1922:   }
        !          1923: 
        !          1924:   if (length) {
        !          1925:     /* spurious leftover data */
        !          1926:       zlog (peer->log, LOG_ERR,
        !          1927:            "Tunnel Encap attribute length is bad: %d leftover octets", length);
        !          1928:       bgp_notify_send_with_data (peer,
        !          1929:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1930:                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
        !          1931:                                 startp, total);
        !          1932:       return -1;
        !          1933:   }
        !          1934: 
        !          1935:   return 0;
        !          1936: }
        !          1937: 
1.1       misho    1938: /* BGP unknown attribute treatment. */
                   1939: static bgp_attr_parse_ret_t
1.1.1.2   misho    1940: bgp_attr_unknown (struct bgp_attr_parser_args *args)
1.1       misho    1941: {
1.1.1.3   misho    1942:   bgp_size_t total = args->total;
1.1       misho    1943:   struct transit *transit;
                   1944:   struct attr_extra *attre;
1.1.1.2   misho    1945:   struct peer *const peer = args->peer; 
                   1946:   struct attr *const attr = args->attr;
                   1947:   u_char *const startp = args->startp;
                   1948:   const u_char type = args->type;
                   1949:   const u_char flag = args->flags;  
                   1950:   const bgp_size_t length = args->length;
                   1951:   
1.1       misho    1952: 
                   1953:   if (BGP_DEBUG (normal, NORMAL))
                   1954:   zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
                   1955:              peer->host, type, length);
                   1956:   
                   1957:   if (BGP_DEBUG (events, EVENTS))
                   1958:     zlog (peer->log, LOG_DEBUG, 
                   1959:          "Unknown attribute type %d length %d is received", type, length);
                   1960: 
                   1961:   /* Forward read pointer of input stream. */
                   1962:   stream_forward_getp (peer->ibuf, length);
                   1963: 
                   1964:   /* If any of the mandatory well-known attributes are not recognized,
                   1965:      then the Error Subcode is set to Unrecognized Well-known
                   1966:      Attribute.  The Data field contains the unrecognized attribute
                   1967:      (type, length and value). */
                   1968:   if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
                   1969:     {
1.1.1.2   misho    1970:       return bgp_attr_malformed (args,
1.1       misho    1971:                                  BGP_NOTIFY_UPDATE_UNREC_ATTR,
1.1.1.2   misho    1972:                                  args->total);
1.1       misho    1973:     }
                   1974: 
                   1975:   /* Unrecognized non-transitive optional attributes must be quietly
                   1976:      ignored and not passed along to other BGP peers. */
                   1977:   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
                   1978:     return BGP_ATTR_PARSE_PROCEED;
                   1979: 
                   1980:   /* If a path with recognized transitive optional attribute is
                   1981:      accepted and passed along to other BGP peers and the Partial bit
                   1982:      in the Attribute Flags octet is set to 1 by some previous AS, it
                   1983:      is not set back to 0 by the current AS. */
                   1984:   SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
                   1985: 
                   1986:   /* Store transitive attribute to the end of attr->transit. */
                   1987:   if (! ((attre = bgp_attr_extra_get(attr))->transit) )
                   1988:       attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
                   1989: 
                   1990:   transit = attre->transit;
                   1991: 
                   1992:   if (transit->val)
                   1993:     transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, 
                   1994:                             transit->length + total);
                   1995:   else
                   1996:     transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
                   1997: 
                   1998:   memcpy (transit->val + transit->length, startp, total);
                   1999:   transit->length += total;
                   2000: 
                   2001:   return BGP_ATTR_PARSE_PROCEED;
                   2002: }
                   2003: 
1.1.1.4 ! misho    2004: /* Well-known attribute check. */
        !          2005: static int
        !          2006: bgp_attr_check (struct peer *peer, struct attr *attr)
        !          2007: {
        !          2008:   u_char type = 0;
        !          2009:   
        !          2010:   /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
        !          2011:    * empty UPDATE.  */
        !          2012:   if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
        !          2013:     return BGP_ATTR_PARSE_PROCEED;
        !          2014:   
        !          2015:   /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
        !          2016:      to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
        !          2017:      are present, it should.  Check for any other attribute being present
        !          2018:      instead.
        !          2019:    */
        !          2020:   if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI))
        !          2021:     return BGP_ATTR_PARSE_PROCEED;
        !          2022:   
        !          2023:   if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
        !          2024:     type = BGP_ATTR_ORIGIN;
        !          2025: 
        !          2026:   if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
        !          2027:     type = BGP_ATTR_AS_PATH;
        !          2028:   
        !          2029:   /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and
        !          2030:    * NLRI is empty. We can't easily check NLRI empty here though.
        !          2031:    */
        !          2032:   if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
        !          2033:       && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)))
        !          2034:     type = BGP_ATTR_NEXT_HOP;
        !          2035:   
        !          2036:   if (peer->sort == BGP_PEER_IBGP
        !          2037:       && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
        !          2038:     type = BGP_ATTR_LOCAL_PREF;
        !          2039: 
        !          2040:   if (type)
        !          2041:     {
        !          2042:       zlog (peer->log, LOG_WARNING, 
        !          2043:            "%s Missing well-known attribute %d / %s",
        !          2044:            peer->host, type, LOOKUP (attr_str, type));
        !          2045:       bgp_notify_send_with_data (peer, 
        !          2046:                                 BGP_NOTIFY_UPDATE_ERR, 
        !          2047:                                 BGP_NOTIFY_UPDATE_MISS_ATTR,
        !          2048:                                 &type, 1);
        !          2049:       return BGP_ATTR_PARSE_ERROR;
        !          2050:     }
        !          2051:   return BGP_ATTR_PARSE_PROCEED;
        !          2052: }
        !          2053: 
1.1       misho    2054: /* Read attribute of update packet.  This function is called from
1.1.1.3   misho    2055:    bgp_update_receive() in bgp_packet.c.  */
1.1       misho    2056: bgp_attr_parse_ret_t
                   2057: bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
                   2058:                struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
                   2059: {
                   2060:   int ret;
                   2061:   u_char flag = 0;
                   2062:   u_char type = 0;
                   2063:   bgp_size_t length;
                   2064:   u_char *startp, *endp;
                   2065:   u_char *attr_endp;
                   2066:   u_char seen[BGP_ATTR_BITMAP_SIZE];
                   2067:   /* we need the as4_path only until we have synthesized the as_path with it */
                   2068:   /* same goes for as4_aggregator */
                   2069:   struct aspath *as4_path = NULL;
                   2070:   as_t as4_aggregator = 0;
1.1.1.4 ! misho    2071:   struct in_addr as4_aggregator_addr = { .s_addr = 0 };
1.1       misho    2072: 
                   2073:   /* Initialize bitmap. */
                   2074:   memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
                   2075: 
                   2076:   /* End pointer of BGP attribute. */
                   2077:   endp = BGP_INPUT_PNT (peer) + size;
                   2078:   
                   2079:   /* Get attributes to the end of attribute length. */
                   2080:   while (BGP_INPUT_PNT (peer) < endp)
                   2081:     {
                   2082:       /* Check remaining length check.*/
                   2083:       if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
                   2084:        {
                   2085:          /* XXX warning: long int format, int arg (arg 5) */
                   2086:          zlog (peer->log, LOG_WARNING, 
                   2087:                "%s: error BGP attribute length %lu is smaller than min len",
                   2088:                peer->host,
                   2089:                (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
                   2090: 
                   2091:          bgp_notify_send (peer, 
                   2092:                           BGP_NOTIFY_UPDATE_ERR, 
                   2093:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
                   2094:          return BGP_ATTR_PARSE_ERROR;
                   2095:        }
                   2096: 
                   2097:       /* Fetch attribute flag and type. */
                   2098:       startp = BGP_INPUT_PNT (peer);
1.1.1.2   misho    2099:       /* "The lower-order four bits of the Attribute Flags octet are
                   2100:          unused.  They MUST be zero when sent and MUST be ignored when
                   2101:          received." */
                   2102:       flag = 0xF0 & stream_getc (BGP_INPUT (peer));
1.1       misho    2103:       type = stream_getc (BGP_INPUT (peer));
                   2104: 
                   2105:       /* Check whether Extended-Length applies and is in bounds */
                   2106:       if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
                   2107:           && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
                   2108:        {
                   2109:          zlog (peer->log, LOG_WARNING, 
                   2110:                "%s: Extended length set, but just %lu bytes of attr header",
                   2111:                peer->host,
                   2112:                (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
                   2113: 
                   2114:          bgp_notify_send (peer, 
                   2115:                           BGP_NOTIFY_UPDATE_ERR, 
                   2116:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
                   2117:          return BGP_ATTR_PARSE_ERROR;
                   2118:        }
1.1.1.2   misho    2119:       
1.1       misho    2120:       /* Check extended attribue length bit. */
                   2121:       if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
                   2122:        length = stream_getw (BGP_INPUT (peer));
                   2123:       else
                   2124:        length = stream_getc (BGP_INPUT (peer));
                   2125:       
                   2126:       /* If any attribute appears more than once in the UPDATE
                   2127:         message, then the Error Subcode is set to Malformed Attribute
                   2128:         List. */
                   2129: 
                   2130:       if (CHECK_BITMAP (seen, type))
                   2131:        {
                   2132:          zlog (peer->log, LOG_WARNING,
                   2133:                "%s: error BGP attribute type %d appears twice in a message",
                   2134:                peer->host, type);
                   2135: 
                   2136:          bgp_notify_send (peer, 
                   2137:                           BGP_NOTIFY_UPDATE_ERR, 
                   2138:                           BGP_NOTIFY_UPDATE_MAL_ATTR);
                   2139:          return BGP_ATTR_PARSE_ERROR;
                   2140:        }
                   2141: 
                   2142:       /* Set type to bitmap to check duplicate attribute.  `type' is
                   2143:         unsigned char so it never overflow bitmap range. */
                   2144: 
                   2145:       SET_BITMAP (seen, type);
                   2146: 
                   2147:       /* Overflow check. */
                   2148:       attr_endp =  BGP_INPUT_PNT (peer) + length;
                   2149: 
                   2150:       if (attr_endp > endp)
                   2151:        {
                   2152:          zlog (peer->log, LOG_WARNING, 
                   2153:                "%s: BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p", peer->host, type, length, size, attr_endp, endp);
                   2154:          bgp_notify_send (peer, 
                   2155:                           BGP_NOTIFY_UPDATE_ERR, 
                   2156:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
                   2157:          return BGP_ATTR_PARSE_ERROR;
                   2158:        }
1.1.1.2   misho    2159:        
                   2160:         struct bgp_attr_parser_args attr_args = {
                   2161:           .peer = peer,
                   2162:           .length = length,
                   2163:           .attr = attr,
                   2164:           .type = type,
                   2165:           .flags = flag,
                   2166:           .startp = startp,
                   2167:           .total = attr_endp - startp,
                   2168:         };
                   2169:       
                   2170:        
                   2171:       /* If any recognized attribute has Attribute Flags that conflict
                   2172:          with the Attribute Type Code, then the Error Subcode is set to
                   2173:          Attribute Flags Error.  The Data field contains the erroneous
                   2174:          attribute (type, length and value). */
                   2175:       if (bgp_attr_flag_invalid (&attr_args))
                   2176:         {
                   2177:           bgp_attr_parse_ret_t ret;
                   2178:           ret = bgp_attr_malformed (&attr_args,
                   2179:                                     BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                   2180:                                     attr_args.total);
                   2181:           if (ret == BGP_ATTR_PARSE_PROCEED)
                   2182:             continue;
                   2183:           return ret;
                   2184:         }
1.1       misho    2185: 
                   2186:       /* OK check attribute and store it's value. */
                   2187:       switch (type)
                   2188:        {
                   2189:        case BGP_ATTR_ORIGIN:
1.1.1.2   misho    2190:          ret = bgp_attr_origin (&attr_args);
1.1       misho    2191:          break;
                   2192:        case BGP_ATTR_AS_PATH:
1.1.1.2   misho    2193:          ret = bgp_attr_aspath (&attr_args);
1.1       misho    2194:          break;
                   2195:        case BGP_ATTR_AS4_PATH:
1.1.1.2   misho    2196:          ret = bgp_attr_as4_path (&attr_args, &as4_path);
1.1       misho    2197:          break;
                   2198:        case BGP_ATTR_NEXT_HOP: 
1.1.1.2   misho    2199:          ret = bgp_attr_nexthop (&attr_args);
1.1       misho    2200:          break;
                   2201:        case BGP_ATTR_MULTI_EXIT_DISC:
1.1.1.2   misho    2202:          ret = bgp_attr_med (&attr_args);
1.1       misho    2203:          break;
                   2204:        case BGP_ATTR_LOCAL_PREF:
1.1.1.2   misho    2205:          ret = bgp_attr_local_pref (&attr_args);
1.1       misho    2206:          break;
                   2207:        case BGP_ATTR_ATOMIC_AGGREGATE:
1.1.1.2   misho    2208:          ret = bgp_attr_atomic (&attr_args);
1.1       misho    2209:          break;
                   2210:        case BGP_ATTR_AGGREGATOR:
1.1.1.2   misho    2211:          ret = bgp_attr_aggregator (&attr_args);
1.1       misho    2212:          break;
                   2213:        case BGP_ATTR_AS4_AGGREGATOR:
1.1.1.2   misho    2214:          ret = bgp_attr_as4_aggregator (&attr_args,
                   2215:                                         &as4_aggregator,
1.1       misho    2216:                                         &as4_aggregator_addr);
                   2217:          break;
                   2218:        case BGP_ATTR_COMMUNITIES:
1.1.1.2   misho    2219:          ret = bgp_attr_community (&attr_args);
1.1       misho    2220:          break;
                   2221:        case BGP_ATTR_ORIGINATOR_ID:
1.1.1.2   misho    2222:          ret = bgp_attr_originator_id (&attr_args);
1.1       misho    2223:          break;
                   2224:        case BGP_ATTR_CLUSTER_LIST:
1.1.1.2   misho    2225:          ret = bgp_attr_cluster_list (&attr_args);
1.1       misho    2226:          break;
                   2227:        case BGP_ATTR_MP_REACH_NLRI:
1.1.1.2   misho    2228:          ret = bgp_mp_reach_parse (&attr_args, mp_update);
1.1       misho    2229:          break;
                   2230:        case BGP_ATTR_MP_UNREACH_NLRI:
1.1.1.2   misho    2231:          ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
1.1       misho    2232:          break;
                   2233:        case BGP_ATTR_EXT_COMMUNITIES:
1.1.1.2   misho    2234:          ret = bgp_attr_ext_communities (&attr_args);
1.1       misho    2235:          break;
1.1.1.4 ! misho    2236:         case BGP_ATTR_ENCAP:
        !          2237:           ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
        !          2238:           break;
1.1       misho    2239:        default:
1.1.1.2   misho    2240:          ret = bgp_attr_unknown (&attr_args);
1.1       misho    2241:          break;
                   2242:        }
                   2243:       
1.1.1.4 ! misho    2244:       if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS)
        !          2245:        {
        !          2246:          bgp_notify_send (peer, 
        !          2247:                           BGP_NOTIFY_UPDATE_ERR,
        !          2248:                           BGP_NOTIFY_UPDATE_MAL_ATTR);
        !          2249:          ret = BGP_ATTR_PARSE_ERROR;
        !          2250:        }
        !          2251: 
1.1       misho    2252:       /* If hard error occured immediately return to the caller. */
                   2253:       if (ret == BGP_ATTR_PARSE_ERROR)
                   2254:         {
                   2255:           zlog (peer->log, LOG_WARNING,
                   2256:                 "%s: Attribute %s, parse error", 
                   2257:                 peer->host, 
                   2258:                 LOOKUP (attr_str, type));
                   2259:           if (as4_path)
                   2260:             aspath_unintern (&as4_path);
                   2261:           return ret;
                   2262:         }
                   2263:       if (ret == BGP_ATTR_PARSE_WITHDRAW)
                   2264:         {
                   2265:           
                   2266:           zlog (peer->log, LOG_WARNING,
                   2267:                 "%s: Attribute %s, parse error - treating as withdrawal",
                   2268:                 peer->host,
                   2269:                 LOOKUP (attr_str, type));
                   2270:           if (as4_path)
                   2271:             aspath_unintern (&as4_path);
                   2272:           return ret;
                   2273:         }
                   2274:       
                   2275:       /* Check the fetched length. */
                   2276:       if (BGP_INPUT_PNT (peer) != attr_endp)
                   2277:        {
                   2278:          zlog (peer->log, LOG_WARNING, 
                   2279:                "%s: BGP attribute %s, fetch error", 
                   2280:                 peer->host, LOOKUP (attr_str, type));
                   2281:          bgp_notify_send (peer, 
                   2282:                           BGP_NOTIFY_UPDATE_ERR, 
                   2283:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
                   2284:           if (as4_path)
                   2285:             aspath_unintern (&as4_path);
                   2286:          return BGP_ATTR_PARSE_ERROR;
                   2287:        }
                   2288:     }
                   2289:   /* Check final read pointer is same as end pointer. */
                   2290:   if (BGP_INPUT_PNT (peer) != endp)
                   2291:     {
                   2292:       zlog (peer->log, LOG_WARNING, 
                   2293:            "%s: BGP attribute %s, length mismatch",
                   2294:            peer->host, LOOKUP (attr_str, type));
                   2295:       bgp_notify_send (peer, 
                   2296:                       BGP_NOTIFY_UPDATE_ERR, 
                   2297:                       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
                   2298:       if (as4_path)
                   2299:         aspath_unintern (&as4_path);
                   2300:       return BGP_ATTR_PARSE_ERROR;
                   2301:     }
1.1.1.4 ! misho    2302:   
        !          2303:   /* Check all mandatory well-known attributes are present */
        !          2304:   {
        !          2305:     bgp_attr_parse_ret_t ret;
        !          2306:     if ((ret = bgp_attr_check (peer, attr)) < 0)
        !          2307:       {
        !          2308:         if (as4_path)
        !          2309:           aspath_unintern (&as4_path);
        !          2310:         return ret;
        !          2311:       }
        !          2312:   }
        !          2313:   
1.1       misho    2314:   /* 
                   2315:    * At this place we can see whether we got AS4_PATH and/or
                   2316:    * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
                   2317:    * We can not do this before we've read all attributes because
                   2318:    * the as4 handling does not say whether AS4_PATH has to be sent
                   2319:    * after AS_PATH or not - and when AS4_AGGREGATOR will be send
                   2320:    * in relationship to AGGREGATOR.
                   2321:    * So, to be defensive, we are not relying on any order and read
                   2322:    * all attributes first, including these 32bit ones, and now,
                   2323:    * afterwards, we look what and if something is to be done for as4.
1.1.1.4 ! misho    2324:    *
        !          2325:    * It is possible to not have AS_PATH, e.g. GR EoR and sole
        !          2326:    * MP_UNREACH_NLRI.
1.1       misho    2327:    */
1.1.1.4 ! misho    2328:   /* actually... this doesn't ever return failure currently, but
        !          2329:    * better safe than sorry */
        !          2330:   if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))
        !          2331:       && bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1.1       misho    2332:                                 as4_aggregator, &as4_aggregator_addr))
                   2333:     {
1.1.1.4 ! misho    2334:       bgp_notify_send (peer, 
        !          2335:                       BGP_NOTIFY_UPDATE_ERR,
        !          2336:                       BGP_NOTIFY_UPDATE_MAL_ATTR);
1.1       misho    2337:       if (as4_path)
                   2338:         aspath_unintern (&as4_path);
                   2339:       return BGP_ATTR_PARSE_ERROR;
                   2340:     }
                   2341: 
                   2342:   /* At this stage, we have done all fiddling with as4, and the
                   2343:    * resulting info is in attr->aggregator resp. attr->aspath
                   2344:    * so we can chuck as4_aggregator and as4_path alltogether in
                   2345:    * order to save memory
                   2346:    */
                   2347:   if (as4_path)
                   2348:     {
                   2349:       aspath_unintern (&as4_path); /* unintern - it is in the hash */
                   2350:       /* The flag that we got this is still there, but that does not
                   2351:        * do any trouble
                   2352:        */
                   2353:     }
                   2354:   /*
                   2355:    * The "rest" of the code does nothing with as4_aggregator.
                   2356:    * there is no memory attached specifically which is not part
                   2357:    * of the attr.
                   2358:    * so ignoring just means do nothing.
                   2359:    */
                   2360:   /*
                   2361:    * Finally do the checks on the aspath we did not do yet
                   2362:    * because we waited for a potentially synthesized aspath.
                   2363:    */
                   2364:   if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
                   2365:     {
1.1.1.2   misho    2366:       ret = bgp_attr_aspath_check (peer, attr);
1.1       misho    2367:       if (ret != BGP_ATTR_PARSE_PROCEED)
                   2368:        return ret;
                   2369:     }
                   2370: 
                   2371:   /* Finally intern unknown attribute. */
                   2372:   if (attr->extra && attr->extra->transit)
                   2373:     attr->extra->transit = transit_intern (attr->extra->transit);
                   2374: 
                   2375:   return BGP_ATTR_PARSE_PROCEED;
                   2376: }
                   2377: 
1.1.1.4 ! misho    2378: int stream_put_prefix (struct stream *, struct prefix *);
1.1       misho    2379: 
1.1.1.4 ! misho    2380: size_t
        !          2381: bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
        !          2382:                         struct attr *attr)
        !          2383: {
        !          2384:   size_t sizep;
        !          2385: 
        !          2386:   /* Set extended bit always to encode the attribute length as 2 bytes */
        !          2387:   stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
        !          2388:   stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
        !          2389:   sizep = stream_get_endp (s);
        !          2390:   stream_putw (s, 0);  /* Marker: Attribute length. */
1.1       misho    2391: 
1.1.1.4 ! misho    2392:   stream_putw (s, afi);
        !          2393:   stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
1.1       misho    2394: 
1.1.1.4 ! misho    2395:   /* Nexthop */
        !          2396:   switch (afi)
        !          2397:     {
        !          2398:     case AFI_IP:
        !          2399:       switch (safi)
        !          2400:        {
        !          2401:        case SAFI_MULTICAST:
        !          2402:          stream_putc (s, 4);
        !          2403:          stream_put_ipv4 (s, attr->nexthop.s_addr);
        !          2404:          break;
        !          2405:        case SAFI_MPLS_VPN:
        !          2406:          stream_putc (s, 12);
        !          2407:          stream_putl (s, 0);   /* RD = 0, per RFC */
        !          2408:          stream_putl (s, 0);
        !          2409:          stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
        !          2410:          break;
        !          2411:        case SAFI_ENCAP:
        !          2412:          stream_putc (s, 4);
        !          2413:          stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
        !          2414:          break;
        !          2415:        case SAFI_UNICAST:      /* invalid for IPv4 */
        !          2416:        default:
        !          2417:          break;
        !          2418:        }
        !          2419:       break;
        !          2420:     case AFI_IP6:
        !          2421:       switch (safi)
        !          2422:       {
        !          2423:       case SAFI_UNICAST:
        !          2424:       case SAFI_MULTICAST:
        !          2425:        {
        !          2426:          struct attr_extra *attre = attr->extra;
1.1       misho    2427: 
1.1.1.4 ! misho    2428:          assert (attr->extra);
        !          2429:          stream_putc (s, attre->mp_nexthop_len);
        !          2430:          stream_put (s, &attre->mp_nexthop_global, 16);
        !          2431:          if (attre->mp_nexthop_len == 32)
        !          2432:            stream_put (s, &attre->mp_nexthop_local, 16);
        !          2433:        }
        !          2434:        break;
        !          2435:       case SAFI_MPLS_VPN:
        !          2436:        {
        !          2437:          struct attr_extra *attre = attr->extra;
        !          2438: 
        !          2439:          assert (attr->extra);
        !          2440:           if (attre->mp_nexthop_len == 16) {
        !          2441:             stream_putc (s, 24);
        !          2442:             stream_putl (s, 0);   /* RD = 0, per RFC */
        !          2443:             stream_putl (s, 0);
        !          2444:             stream_put (s, &attre->mp_nexthop_global, 16);
        !          2445:           } else if (attre->mp_nexthop_len == 32) {
        !          2446:             stream_putc (s, 48);
        !          2447:             stream_putl (s, 0);   /* RD = 0, per RFC */
        !          2448:             stream_putl (s, 0);
        !          2449:             stream_put (s, &attre->mp_nexthop_global, 16);
        !          2450:             stream_putl (s, 0);   /* RD = 0, per RFC */
        !          2451:             stream_putl (s, 0);
        !          2452:             stream_put (s, &attre->mp_nexthop_local, 16);
        !          2453:           }
        !          2454:         }
        !          2455:        break;
        !          2456:        case SAFI_ENCAP:
        !          2457:           assert (attr->extra);
        !          2458:           stream_putc (s, 16);
        !          2459:          stream_put (s, &attr->extra->mp_nexthop_global, 16);
        !          2460:          break;
        !          2461:       default:
        !          2462:        break;
        !          2463:       }
        !          2464:       break;
        !          2465:     default:
        !          2466:       break;
        !          2467:     }
        !          2468: 
        !          2469:   /* SNPA */
        !          2470:   stream_putc (s, 0);
        !          2471:   return sizep;
        !          2472: }
        !          2473: 
        !          2474: void
        !          2475: bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
        !          2476:                          struct prefix *p, struct prefix_rd *prd,
        !          2477:                          u_char *tag)
        !          2478: {
        !          2479:   if (safi == SAFI_MPLS_VPN)
1.1       misho    2480:     {
1.1.1.4 ! misho    2481:       /* Tag, RD, Prefix write. */
        !          2482:       stream_putc (s, p->prefixlen + 88);
        !          2483:       stream_put (s, tag, 3);
        !          2484:       stream_put (s, prd->val, 8);
        !          2485:       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1.1       misho    2486:     }
1.1.1.4 ! misho    2487:   else
        !          2488:     stream_put_prefix (s, p);
        !          2489: }
        !          2490: 
        !          2491: size_t
        !          2492: bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p)
        !          2493: {
        !          2494:   int size = PSIZE (p->prefixlen);
        !          2495:   if (safi == SAFI_MPLS_VPN)
        !          2496:       size += 88;
        !          2497:   return size;
        !          2498: }
        !          2499: 
        !          2500: /*
        !          2501:  * Encodes the tunnel encapsulation attribute
        !          2502:  */
        !          2503: static void
        !          2504: bgp_packet_mpattr_tea(
        !          2505:     struct bgp         *bgp,
        !          2506:     struct peer                *peer,
        !          2507:     struct stream      *s,
        !          2508:     struct attr                *attr,
        !          2509:     uint8_t            attrtype)
        !          2510: {
        !          2511:     unsigned int                       attrlenfield = 0;
        !          2512:     unsigned int                       attrhdrlen   = 0;
        !          2513:     struct bgp_attr_encap_subtlv       *subtlvs;
        !          2514:     struct bgp_attr_encap_subtlv       *st;
        !          2515:     const char                         *attrname;
        !          2516: 
        !          2517:     if (!attr || !attr->extra)
        !          2518:        return;
        !          2519: 
        !          2520:     switch (attrtype) {
        !          2521:        case BGP_ATTR_ENCAP:
        !          2522:            attrname = "Tunnel Encap";
        !          2523:            subtlvs = attr->extra->encap_subtlvs;
        !          2524: 
        !          2525:            /*
        !          2526:             * The tunnel encap attr has an "outer" tlv.
        !          2527:             * T = tunneltype,
        !          2528:             * L = total length of subtlvs,
        !          2529:             * V = concatenated subtlvs.
        !          2530:             */
        !          2531:            attrlenfield = 2 + 2;       /* T + L */
        !          2532:             attrhdrlen   = 1 + 1;      /* subTLV T + L */
        !          2533:            break;
        !          2534: 
        !          2535:        default:
        !          2536:            assert(0);
        !          2537:     }
        !          2538: 
        !          2539: 
        !          2540:     /* if no tlvs, don't make attr */
        !          2541:     if (subtlvs == NULL)
        !          2542:        return;
        !          2543: 
        !          2544:     /* compute attr length */
        !          2545:     for (st = subtlvs; st; st = st->next) {
        !          2546:        attrlenfield += (attrhdrlen + st->length);
        !          2547:     }
        !          2548: 
        !          2549:     if (attrlenfield > 0xffff) {
        !          2550:        zlog (peer->log, LOG_ERR,
        !          2551:            "%s attribute is too long (length=%d), can't send it",
        !          2552:            attrname,
        !          2553:            attrlenfield);
        !          2554:        return;
        !          2555:     }
        !          2556: 
        !          2557:     if (attrlenfield > 0xff) {
        !          2558:        /* 2-octet length field */
        !          2559:        stream_putc (s,
        !          2560:            BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
        !          2561:        stream_putc (s, attrtype);
        !          2562:        stream_putw (s, attrlenfield & 0xffff);
        !          2563:     } else {
        !          2564:        /* 1-octet length field */
        !          2565:        stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
        !          2566:        stream_putc (s, attrtype);
        !          2567:        stream_putc (s, attrlenfield & 0xff);
        !          2568:     }
        !          2569: 
        !          2570:     if (attrtype == BGP_ATTR_ENCAP) {
        !          2571:        /* write outer T+L */
        !          2572:        stream_putw(s, attr->extra->encap_tunneltype);
        !          2573:        stream_putw(s, attrlenfield - 4);
        !          2574:     }
        !          2575: 
        !          2576:     /* write each sub-tlv */
        !          2577:     for (st = subtlvs; st; st = st->next) {
        !          2578:         if (attrtype == BGP_ATTR_ENCAP) {
        !          2579:             stream_putc (s, st->type);
        !          2580:             stream_putc (s, st->length);
        !          2581:         }
        !          2582:        stream_put (s, st->value, st->length);
        !          2583:     }
        !          2584: }
        !          2585: 
        !          2586: void
        !          2587: bgp_packet_mpattr_end (struct stream *s, size_t sizep)
        !          2588: {
        !          2589:   /* Set MP attribute length. Don't count the (2) bytes used to encode
        !          2590:      the attr length */
        !          2591:   stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2);
1.1       misho    2592: }
                   2593: 
                   2594: /* Make attribute packet. */
                   2595: bgp_size_t
                   2596: bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1.1.1.4 ! misho    2597:                      struct stream *s, struct attr *attr,
        !          2598:                      struct prefix *p, afi_t afi, safi_t safi,
        !          2599:                      struct peer *from, struct prefix_rd *prd, u_char *tag)
1.1       misho    2600: {
                   2601:   size_t cp;
                   2602:   size_t aspath_sizep;
                   2603:   struct aspath *aspath;
                   2604:   int send_as4_path = 0;
                   2605:   int send_as4_aggregator = 0;
                   2606:   int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
                   2607: 
                   2608:   if (! bgp)
                   2609:     bgp = bgp_get_default ();
                   2610: 
                   2611:   /* Remember current pointer. */
                   2612:   cp = stream_get_endp (s);
                   2613: 
1.1.1.4 ! misho    2614:   if (p && !(afi == AFI_IP && safi == SAFI_UNICAST))
        !          2615:     {
        !          2616:       size_t mpattrlen_pos = 0;
        !          2617:       mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr);
        !          2618:       bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
        !          2619:       bgp_packet_mpattr_end(s, mpattrlen_pos);
        !          2620:     }
        !          2621: 
1.1       misho    2622:   /* Origin attribute. */
                   2623:   stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   2624:   stream_putc (s, BGP_ATTR_ORIGIN);
                   2625:   stream_putc (s, 1);
                   2626:   stream_putc (s, attr->origin);
                   2627: 
                   2628:   /* AS path attribute. */
                   2629: 
                   2630:   /* If remote-peer is EBGP */
1.1.1.3   misho    2631:   if (peer->sort == BGP_PEER_EBGP
1.1       misho    2632:       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
                   2633:          || attr->aspath->segments == NULL)
                   2634:       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
                   2635:     {    
                   2636:       aspath = aspath_dup (attr->aspath);
                   2637: 
                   2638:       if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
                   2639:        {
                   2640:          /* Strip the confed info, and then stuff our path CONFED_ID
                   2641:             on the front */
                   2642:          aspath = aspath_delete_confed_seq (aspath);
                   2643:          aspath = aspath_add_seq (aspath, bgp->confed_id);
                   2644:        }
                   2645:       else
                   2646:        {
1.1.1.3   misho    2647:          if (peer->change_local_as) {
                   2648:             /* If replace-as is specified, we only use the change_local_as when
                   2649:                advertising routes. */
                   2650:             if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
                   2651:               aspath = aspath_add_seq (aspath, peer->local_as);
                   2652:             }
1.1       misho    2653:            aspath = aspath_add_seq (aspath, peer->change_local_as);
1.1.1.3   misho    2654:           } else {
                   2655:             aspath = aspath_add_seq (aspath, peer->local_as);
                   2656:           }
1.1       misho    2657:        }
                   2658:     }
1.1.1.3   misho    2659:   else if (peer->sort == BGP_PEER_CONFED)
1.1       misho    2660:     {
                   2661:       /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
                   2662:       aspath = aspath_dup (attr->aspath);
                   2663:       aspath = aspath_add_confed_seq (aspath, peer->local_as);
                   2664:     }
                   2665:   else
                   2666:     aspath = attr->aspath;
                   2667: 
                   2668:   /* If peer is not AS4 capable, then:
                   2669:    * - send the created AS_PATH out as AS4_PATH (optional, transitive),
                   2670:    *   but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
                   2671:    *   types are in it (i.e. exclude them if they are there)
                   2672:    *   AND do this only if there is at least one asnum > 65535 in the path!
                   2673:    * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
                   2674:    *   all ASnums > 65535 to BGP_AS_TRANS
                   2675:    */
                   2676: 
                   2677:   stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
                   2678:   stream_putc (s, BGP_ATTR_AS_PATH);
                   2679:   aspath_sizep = stream_get_endp (s);
                   2680:   stream_putw (s, 0);
                   2681:   stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
                   2682:   
                   2683:   /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs 
                   2684:    * in the path
                   2685:    */
                   2686:   if (!use32bit && aspath_has_as4 (aspath))
                   2687:       send_as4_path = 1; /* we'll do this later, at the correct place */
                   2688:   
                   2689:   /* Nexthop attribute. */
1.1.1.4 ! misho    2690:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP &&
        !          2691:     safi ==  SAFI_UNICAST)   /* only write NH attr for unicast safi */
1.1       misho    2692:     {
                   2693:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   2694:       stream_putc (s, BGP_ATTR_NEXT_HOP);
                   2695:       stream_putc (s, 4);
                   2696:       if (safi == SAFI_MPLS_VPN)
                   2697:        {
                   2698:          if (attr->nexthop.s_addr == 0)
                   2699:            stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
                   2700:          else
                   2701:            stream_put_ipv4 (s, attr->nexthop.s_addr);
                   2702:        }
                   2703:       else
                   2704:        stream_put_ipv4 (s, attr->nexthop.s_addr);
                   2705:     }
                   2706: 
                   2707:   /* MED attribute. */
                   2708:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
                   2709:     {
                   2710:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
                   2711:       stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
                   2712:       stream_putc (s, 4);
                   2713:       stream_putl (s, attr->med);
                   2714:     }
                   2715: 
                   2716:   /* Local preference. */
1.1.1.3   misho    2717:   if (peer->sort == BGP_PEER_IBGP ||
                   2718:       peer->sort == BGP_PEER_CONFED)
1.1       misho    2719:     {
                   2720:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   2721:       stream_putc (s, BGP_ATTR_LOCAL_PREF);
                   2722:       stream_putc (s, 4);
                   2723:       stream_putl (s, attr->local_pref);
                   2724:     }
                   2725: 
                   2726:   /* Atomic aggregate. */
                   2727:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
                   2728:     {
                   2729:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   2730:       stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
                   2731:       stream_putc (s, 0);
                   2732:     }
                   2733: 
                   2734:   /* Aggregator. */
                   2735:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
                   2736:     {
                   2737:       assert (attr->extra);
                   2738:       
                   2739:       /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
                   2740:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   2741:       stream_putc (s, BGP_ATTR_AGGREGATOR);
                   2742:       
                   2743:       if (use32bit)
                   2744:         {
                   2745:           /* AS4 capable peer */
                   2746:           stream_putc (s, 8);
                   2747:           stream_putl (s, attr->extra->aggregator_as);
                   2748:         }
                   2749:       else
                   2750:         {
                   2751:           /* 2-byte AS peer */
                   2752:           stream_putc (s, 6);
                   2753:           
                   2754:           /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
                   2755:           if ( attr->extra->aggregator_as > 65535 )
                   2756:             {
                   2757:               stream_putw (s, BGP_AS_TRANS);
                   2758:               
                   2759:               /* we have to send AS4_AGGREGATOR, too.
                   2760:                * we'll do that later in order to send attributes in ascending
                   2761:                * order.
                   2762:                */
                   2763:               send_as4_aggregator = 1;
                   2764:             }
                   2765:           else
                   2766:             stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
                   2767:         }
                   2768:       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
                   2769:     }
                   2770: 
                   2771:   /* Community attribute. */
                   2772:   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) 
                   2773:       && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
                   2774:     {
                   2775:       if (attr->community->size * 4 > 255)
                   2776:        {
                   2777:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
                   2778:          stream_putc (s, BGP_ATTR_COMMUNITIES);
                   2779:          stream_putw (s, attr->community->size * 4);
                   2780:        }
                   2781:       else
                   2782:        {
                   2783:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   2784:          stream_putc (s, BGP_ATTR_COMMUNITIES);
                   2785:          stream_putc (s, attr->community->size * 4);
                   2786:        }
                   2787:       stream_put (s, attr->community->val, attr->community->size * 4);
                   2788:     }
                   2789: 
                   2790:   /* Route Reflector. */
1.1.1.3   misho    2791:   if (peer->sort == BGP_PEER_IBGP
1.1       misho    2792:       && from
1.1.1.3   misho    2793:       && from->sort == BGP_PEER_IBGP)
1.1       misho    2794:     {
                   2795:       /* Originator ID. */
                   2796:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
                   2797:       stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
                   2798:       stream_putc (s, 4);
                   2799: 
                   2800:       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
                   2801:        stream_put_in_addr (s, &attr->extra->originator_id);
                   2802:       else 
                   2803:         stream_put_in_addr (s, &from->remote_id);
                   2804: 
                   2805:       /* Cluster list. */
                   2806:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
                   2807:       stream_putc (s, BGP_ATTR_CLUSTER_LIST);
                   2808:       
                   2809:       if (attr->extra && attr->extra->cluster)
                   2810:        {
                   2811:          stream_putc (s, attr->extra->cluster->length + 4);
                   2812:          /* If this peer configuration's parent BGP has cluster_id. */
                   2813:          if (bgp->config & BGP_CONFIG_CLUSTER_ID)
                   2814:            stream_put_in_addr (s, &bgp->cluster_id);
                   2815:          else
                   2816:            stream_put_in_addr (s, &bgp->router_id);
                   2817:          stream_put (s, attr->extra->cluster->list, 
                   2818:                      attr->extra->cluster->length);
                   2819:        }
                   2820:       else
                   2821:        {
                   2822:          stream_putc (s, 4);
                   2823:          /* If this peer configuration's parent BGP has cluster_id. */
                   2824:          if (bgp->config & BGP_CONFIG_CLUSTER_ID)
                   2825:            stream_put_in_addr (s, &bgp->cluster_id);
                   2826:          else
                   2827:            stream_put_in_addr (s, &bgp->router_id);
                   2828:        }
                   2829:     }
                   2830: 
                   2831:   /* Extended Communities attribute. */
                   2832:   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) 
                   2833:       && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
                   2834:     {
                   2835:       struct attr_extra *attre = attr->extra;
                   2836:       
                   2837:       assert (attre);
                   2838:       
1.1.1.3   misho    2839:       if (peer->sort == BGP_PEER_IBGP
                   2840:           || peer->sort == BGP_PEER_CONFED)
1.1       misho    2841:        {
                   2842:          if (attre->ecommunity->size * 8 > 255)
                   2843:            {
                   2844:              stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
                   2845:              stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
                   2846:              stream_putw (s, attre->ecommunity->size * 8);
                   2847:            }
                   2848:          else
                   2849:            {
                   2850:              stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   2851:              stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
                   2852:              stream_putc (s, attre->ecommunity->size * 8);
                   2853:            }
                   2854:          stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
                   2855:        }
                   2856:       else
                   2857:        {
                   2858:          u_int8_t *pnt;
                   2859:          int tbit;
                   2860:          int ecom_tr_size = 0;
                   2861:          int i;
                   2862: 
                   2863:          for (i = 0; i < attre->ecommunity->size; i++)
                   2864:            {
                   2865:              pnt = attre->ecommunity->val + (i * 8);
                   2866:              tbit = *pnt;
                   2867: 
                   2868:              if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
                   2869:                continue;
                   2870: 
                   2871:              ecom_tr_size++;
                   2872:            }
                   2873: 
                   2874:          if (ecom_tr_size)
                   2875:            {
                   2876:              if (ecom_tr_size * 8 > 255)
                   2877:                {
                   2878:                  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
                   2879:                  stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
                   2880:                  stream_putw (s, ecom_tr_size * 8);
                   2881:                }
                   2882:              else
                   2883:                {
                   2884:                  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   2885:                  stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
                   2886:                  stream_putc (s, ecom_tr_size * 8);
                   2887:                }
                   2888: 
                   2889:              for (i = 0; i < attre->ecommunity->size; i++)
                   2890:                {
                   2891:                  pnt = attre->ecommunity->val + (i * 8);
                   2892:                  tbit = *pnt;
                   2893: 
                   2894:                  if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
                   2895:                    continue;
                   2896: 
                   2897:                  stream_put (s, pnt, 8);
                   2898:                }
                   2899:            }
                   2900:        }
                   2901:     }
                   2902: 
                   2903:   if ( send_as4_path )
                   2904:     {
                   2905:       /* If the peer is NOT As4 capable, AND */
                   2906:       /* there are ASnums > 65535 in path  THEN
                   2907:        * give out AS4_PATH */
                   2908: 
                   2909:       /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
                   2910:        * path segments!
                   2911:        * Hm, I wonder...  confederation things *should* only be at
                   2912:        * the beginning of an aspath, right?  Then we should use
                   2913:        * aspath_delete_confed_seq for this, because it is already
                   2914:        * there! (JK) 
                   2915:        * Folks, talk to me: what is reasonable here!?
                   2916:        */
                   2917:       aspath = aspath_delete_confed_seq (aspath);
                   2918: 
                   2919:       stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
                   2920:       stream_putc (s, BGP_ATTR_AS4_PATH);
                   2921:       aspath_sizep = stream_get_endp (s);
                   2922:       stream_putw (s, 0);
                   2923:       stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
                   2924:     }
                   2925: 
                   2926:   if (aspath != attr->aspath)
                   2927:     aspath_free (aspath);
                   2928: 
                   2929:   if ( send_as4_aggregator ) 
                   2930:     {
                   2931:       assert (attr->extra);
                   2932: 
                   2933:       /* send AS4_AGGREGATOR, at this place */
                   2934:       /* this section of code moved here in order to ensure the correct
                   2935:        * *ascending* order of attributes
                   2936:        */
                   2937:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   2938:       stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
                   2939:       stream_putc (s, 8);
                   2940:       stream_putl (s, attr->extra->aggregator_as);
                   2941:       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
                   2942:     }
1.1.1.4 ! misho    2943: 
        !          2944:   if ((afi == AFI_IP || afi == AFI_IP6) &&
        !          2945:       (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
        !          2946:     {
        !          2947:        /* Tunnel Encap attribute */
        !          2948:        bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
        !          2949:     }
        !          2950: 
1.1       misho    2951:   /* Unknown transit attribute. */
                   2952:   if (attr->extra && attr->extra->transit)
                   2953:     stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
                   2954: 
                   2955:   /* Return total size of attribute. */
                   2956:   return stream_get_endp (s) - cp;
                   2957: }
                   2958: 
1.1.1.4 ! misho    2959: size_t
        !          2960: bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
1.1       misho    2961: {
                   2962:   unsigned long attrlen_pnt;
                   2963: 
1.1.1.4 ! misho    2964:   /* Set extended bit always to encode the attribute length as 2 bytes */
        !          2965:   stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
1.1       misho    2966:   stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
                   2967: 
                   2968:   attrlen_pnt = stream_get_endp (s);
1.1.1.4 ! misho    2969:   stream_putw (s, 0);          /* Length of this attribute. */
1.1       misho    2970: 
1.1.1.4 ! misho    2971:   stream_putw (s, afi);
        !          2972:   stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
        !          2973:   return attrlen_pnt;
        !          2974: }
1.1       misho    2975: 
1.1.1.4 ! misho    2976: void
        !          2977: bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
        !          2978:                             afi_t afi, safi_t safi, struct prefix_rd *prd,
        !          2979:                             u_char *tag)
        !          2980: {
        !          2981:   bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag);
        !          2982: }
1.1       misho    2983: 
1.1.1.4 ! misho    2984: void
        !          2985: bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt)
        !          2986: {
        !          2987:   bgp_packet_mpattr_end (s, attrlen_pnt);
1.1       misho    2988: }
                   2989: 
                   2990: /* Initialization of attribute. */
                   2991: void
                   2992: bgp_attr_init (void)
                   2993: {
                   2994:   aspath_init ();
                   2995:   attrhash_init ();
                   2996:   community_init ();
                   2997:   ecommunity_init ();
                   2998:   cluster_init ();
                   2999:   transit_init ();
                   3000: }
                   3001: 
                   3002: void
                   3003: bgp_attr_finish (void)
                   3004: {
                   3005:   aspath_finish ();
                   3006:   attrhash_finish ();
                   3007:   community_finish ();
                   3008:   ecommunity_finish ();
                   3009:   cluster_finish ();
                   3010:   transit_finish ();
                   3011: }
                   3012: 
                   3013: /* Make attribute packet. */
                   3014: void
                   3015: bgp_dump_routes_attr (struct stream *s, struct attr *attr, 
                   3016:                       struct prefix *prefix)
                   3017: {
                   3018:   unsigned long cp;
                   3019:   unsigned long len;
                   3020:   size_t aspath_lenp;
                   3021:   struct aspath *aspath;
                   3022: 
                   3023:   /* Remember current pointer. */
                   3024:   cp = stream_get_endp (s);
                   3025: 
                   3026:   /* Place holder of length. */
                   3027:   stream_putw (s, 0);
                   3028: 
                   3029:   /* Origin attribute. */
                   3030:   stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   3031:   stream_putc (s, BGP_ATTR_ORIGIN);
                   3032:   stream_putc (s, 1);
                   3033:   stream_putc (s, attr->origin);
                   3034: 
                   3035:   aspath = attr->aspath;
                   3036:   
                   3037:   stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
                   3038:   stream_putc (s, BGP_ATTR_AS_PATH);
                   3039:   aspath_lenp = stream_get_endp (s);
                   3040:   stream_putw (s, 0);
                   3041:   
                   3042:   stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
                   3043: 
                   3044:   /* Nexthop attribute. */
                   3045:   /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
                   3046:   if(prefix != NULL
                   3047:      && prefix->family != AF_INET6
                   3048:      )
                   3049:     {
                   3050:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   3051:       stream_putc (s, BGP_ATTR_NEXT_HOP);
                   3052:       stream_putc (s, 4);
                   3053:       stream_put_ipv4 (s, attr->nexthop.s_addr);
                   3054:     }
                   3055: 
                   3056:   /* MED attribute. */
                   3057:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
                   3058:     {
                   3059:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
                   3060:       stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
                   3061:       stream_putc (s, 4);
                   3062:       stream_putl (s, attr->med);
                   3063:     }
                   3064: 
                   3065:   /* Local preference. */
                   3066:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
                   3067:     {
                   3068:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   3069:       stream_putc (s, BGP_ATTR_LOCAL_PREF);
                   3070:       stream_putc (s, 4);
                   3071:       stream_putl (s, attr->local_pref);
                   3072:     }
                   3073: 
                   3074:   /* Atomic aggregate. */
                   3075:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
                   3076:     {
                   3077:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
                   3078:       stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
                   3079:       stream_putc (s, 0);
                   3080:     }
                   3081: 
                   3082:   /* Aggregator. */
                   3083:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
                   3084:     {
                   3085:       assert (attr->extra);
                   3086:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   3087:       stream_putc (s, BGP_ATTR_AGGREGATOR);
                   3088:       stream_putc (s, 8);
                   3089:       stream_putl (s, attr->extra->aggregator_as);
                   3090:       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
                   3091:     }
                   3092: 
                   3093:   /* Community attribute. */
                   3094:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
                   3095:     {
                   3096:       if (attr->community->size * 4 > 255)
                   3097:        {
                   3098:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
                   3099:          stream_putc (s, BGP_ATTR_COMMUNITIES);
                   3100:          stream_putw (s, attr->community->size * 4);
                   3101:        }
                   3102:       else
                   3103:        {
                   3104:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
                   3105:          stream_putc (s, BGP_ATTR_COMMUNITIES);
                   3106:          stream_putc (s, attr->community->size * 4);
                   3107:        }
                   3108:       stream_put (s, attr->community->val, attr->community->size * 4);
                   3109:     }
                   3110: 
                   3111:   /* Add a MP_NLRI attribute to dump the IPv6 next hop */
                   3112:   if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
                   3113:      (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
                   3114:     {
                   3115:       int sizep;
                   3116:       struct attr_extra *attre = attr->extra;
                   3117:       
                   3118:       stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
                   3119:       stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
                   3120:       sizep = stream_get_endp (s);
                   3121: 
                   3122:       /* MP header */
                   3123:       stream_putc (s, 0);              /* Marker: Attribute length. */
                   3124:       stream_putw(s, AFI_IP6);         /* AFI */
                   3125:       stream_putc(s, SAFI_UNICAST);    /* SAFI */
                   3126: 
                   3127:       /* Next hop */
                   3128:       stream_putc(s, attre->mp_nexthop_len);
                   3129:       stream_put(s, &attre->mp_nexthop_global, 16);
                   3130:       if (attre->mp_nexthop_len == 32)
                   3131:         stream_put(s, &attre->mp_nexthop_local, 16);
                   3132: 
                   3133:       /* SNPA */
                   3134:       stream_putc(s, 0);
                   3135: 
                   3136:       /* Prefix */
                   3137:       stream_put_prefix(s, prefix);
                   3138: 
                   3139:       /* Set MP attribute length. */
                   3140:       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
                   3141:     }
                   3142: 
                   3143:   /* Return total size of attribute. */
                   3144:   len = stream_get_endp (s) - cp - 2;
                   3145:   stream_putw_at (s, cp, len);
                   3146: }

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