LCOV - code coverage report
Current view: top level - bgpd - bgp_open.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 219 458 47.8 %
Date: 2015-11-19 Functions: 10 15 66.7 %

          Line data    Source code
       1             : /* BGP open message handling
       2             :    Copyright (C) 1998, 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 "stream.h"
      26             : #include "thread.h"
      27             : #include "log.h"
      28             : #include "command.h"
      29             : #include "memory.h"
      30             : 
      31             : #include "bgpd/bgpd.h"
      32             : #include "bgpd/bgp_attr.h"
      33             : #include "bgpd/bgp_debug.h"
      34             : #include "bgpd/bgp_fsm.h"
      35             : #include "bgpd/bgp_packet.h"
      36             : #include "bgpd/bgp_open.h"
      37             : #include "bgpd/bgp_aspath.h"
      38             : #include "bgpd/bgp_vty.h"
      39             : 
      40             : /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
      41             :    negotiate remote peer supports extentions or not. But if
      42             :    remote-peer doesn't supports negotiation process itself.  We would
      43             :    like to do manual configuration.
      44             : 
      45             :    So there is many configurable point.  First of all we want set each
      46             :    peer whether we send capability negotiation to the peer or not.
      47             :    Next, if we send capability to the peer we want to set my capabilty
      48             :    inforation at each peer. */
      49             : 
      50             : void
      51           0 : bgp_capability_vty_out (struct vty *vty, struct peer *peer)
      52             : {
      53             :   char *pnt;
      54             :   char *end;
      55             :   struct capability_mp_data mpc;
      56             :   struct capability_header *hdr;
      57             : 
      58           0 :   pnt = peer->notify.data;
      59           0 :   end = pnt + peer->notify.length;
      60             :   
      61           0 :   while (pnt < end)
      62             :     {
      63           0 :       if (pnt + sizeof (struct capability_mp_data) + 2 > end)
      64           0 :         return;
      65             :       
      66           0 :       hdr = (struct capability_header *)pnt;
      67           0 :       if (pnt + hdr->length + 2 > end)
      68           0 :         return;
      69             : 
      70           0 :       memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data));
      71             : 
      72           0 :       if (hdr->code == CAPABILITY_CODE_MP)
      73             :         {
      74           0 :           vty_out (vty, "  Capability error for: Multi protocol ");
      75             : 
      76           0 :           switch (ntohs (mpc.afi))
      77             :             {
      78             :             case AFI_IP:
      79           0 :               vty_out (vty, "AFI IPv4, ");
      80           0 :               break;
      81             :             case AFI_IP6:
      82           0 :               vty_out (vty, "AFI IPv6, ");
      83           0 :               break;
      84             :             default:
      85           0 :               vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
      86           0 :               break;
      87             :             }
      88           0 :           switch (mpc.safi)
      89             :             {
      90             :             case SAFI_UNICAST:
      91           0 :               vty_out (vty, "SAFI Unicast");
      92           0 :               break;
      93             :             case SAFI_MULTICAST:
      94           0 :               vty_out (vty, "SAFI Multicast");
      95           0 :               break;
      96             :             case SAFI_MPLS_LABELED_VPN:
      97           0 :               vty_out (vty, "SAFI MPLS-labeled VPN");
      98           0 :               break;
      99             :             default:
     100           0 :               vty_out (vty, "SAFI Unknown %d ", mpc.safi);
     101           0 :               break;
     102             :             }
     103           0 :           vty_out (vty, "%s", VTY_NEWLINE);
     104             :         }
     105           0 :       else if (hdr->code >= 128)
     106           0 :         vty_out (vty, "  Capability error: vendor specific capability code %d",
     107           0 :                  hdr->code);
     108             :       else
     109           0 :         vty_out (vty, "  Capability error: unknown capability code %d", 
     110           0 :                  hdr->code);
     111             : 
     112           0 :       pnt += hdr->length + 2;
     113             :     }
     114             : }
     115             : 
     116             : static void 
     117          27 : bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
     118             : {
     119          27 :   mpc->afi = stream_getw (s);
     120          27 :   mpc->reserved = stream_getc (s);
     121          27 :   mpc->safi = stream_getc (s);
     122          27 : }
     123             : 
     124             : int
     125          54 : bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
     126             : {
     127          54 :   switch (afi)
     128             :     {
     129             :       case AFI_IP:
     130             : #ifdef HAVE_IPV6
     131             :       case AFI_IP6:
     132             : #endif
     133          52 :         switch (*safi)
     134             :           {
     135             :             /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */
     136             :             case SAFI_MPLS_LABELED_VPN:
     137           4 :               *safi = SAFI_MPLS_VPN;
     138             :             case SAFI_UNICAST:
     139             :             case SAFI_MULTICAST:
     140             :             case SAFI_MPLS_VPN:
     141          52 :               return 1;
     142             :           }
     143             :     }
     144           2 :   zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
     145             :   
     146           2 :   return 0;
     147             : }
     148             : 
     149             : /* Set negotiated capability value. */
     150             : static int
     151          19 : bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
     152             : {
     153             :   struct capability_mp_data mpc;
     154          19 :   struct stream *s = BGP_INPUT (peer);
     155             :   
     156          19 :   bgp_capability_mp_data (s, &mpc);
     157             :   
     158          19 :   if (BGP_DEBUG (normal, NORMAL))
     159          38 :     zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
     160          38 :                peer->host, mpc.afi, mpc.safi);
     161             :   
     162          19 :   if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
     163           1 :     return -1;
     164             :    
     165             :   /* Now safi remapped, and afi/safi are valid array indices */
     166          18 :   peer->afc_recv[mpc.afi][mpc.safi] = 1;
     167             :   
     168          18 :   if (peer->afc[mpc.afi][mpc.safi])
     169          18 :     peer->afc_nego[mpc.afi][mpc.safi] = 1;
     170             :   else 
     171           0 :     return -1;
     172             : 
     173          18 :   return 0;
     174             : }
     175             : 
     176             : static void
     177          10 : bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
     178             :                                 u_char type, u_char mode)
     179             : {
     180          10 :   if (BGP_DEBUG (normal, NORMAL))
     181          10 :     zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
     182             :                peer->host, afi, safi, type, mode);
     183          10 : }
     184             : 
     185             : static const struct message orf_type_str[] =
     186             : {
     187             :   { ORF_TYPE_PREFIX,            "Prefixlist"          },
     188             :   { ORF_TYPE_PREFIX_OLD,        "Prefixlist (old)"    },
     189             : };
     190             : static const int orf_type_str_max = array_size(orf_type_str);
     191             : 
     192             : static const struct message orf_mode_str[] =
     193             : {
     194             :   { ORF_MODE_RECEIVE,   "Receive"     },
     195             :   { ORF_MODE_SEND,      "Send"                },
     196             :   { ORF_MODE_BOTH,      "Both"                },
     197             : };
     198             : static const int orf_mode_str_max = array_size(orf_mode_str);
     199             : 
     200             : static int
     201           8 : bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
     202             : {
     203           8 :   struct stream *s = BGP_INPUT (peer);
     204             :   struct capability_orf_entry entry;
     205             :   afi_t afi;
     206             :   safi_t safi;
     207             :   u_char type;
     208             :   u_char mode;
     209           8 :   u_int16_t sm_cap = 0; /* capability send-mode receive */
     210           8 :   u_int16_t rm_cap = 0; /* capability receive-mode receive */ 
     211             :   int i;
     212             : 
     213             :   /* ORF Entry header */
     214           8 :   bgp_capability_mp_data (s, &entry.mpc);
     215           8 :   entry.num = stream_getc (s);
     216           8 :   afi = entry.mpc.afi;
     217           8 :   safi = entry.mpc.safi;
     218             :   
     219           8 :   if (BGP_DEBUG (normal, NORMAL))
     220          16 :     zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
     221          16 :                 peer->host, entry.mpc.afi, entry.mpc.safi);
     222             : 
     223             :   /* Check AFI and SAFI. */
     224           8 :   if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
     225             :     {
     226           0 :       zlog_info ("%s Addr-family %d/%d not supported."
     227             :                  " Ignoring the ORF capability",
     228           0 :                  peer->host, entry.mpc.afi, entry.mpc.safi);
     229           0 :       return 0;
     230             :     }
     231             :   
     232             :   /* validate number field */
     233           8 :   if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
     234             :     {
     235           0 :       zlog_info ("%s ORF Capability entry length error,"
     236             :                  " Cap length %u, num %u",
     237           0 :                  peer->host, hdr->length, entry.num);
     238           0 :       bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
     239           0 :       return -1;
     240             :     }
     241             : 
     242          26 :   for (i = 0 ; i < entry.num ; i++)
     243             :     {
     244          18 :       type = stream_getc(s);
     245          18 :       mode = stream_getc(s);
     246             :       
     247             :       /* ORF Mode error check */
     248          18 :       switch (mode)
     249             :         {
     250             :           case ORF_MODE_BOTH:
     251             :           case ORF_MODE_SEND:
     252             :           case ORF_MODE_RECEIVE:
     253          18 :             break;
     254             :           default:
     255           0 :             bgp_capability_orf_not_support (peer, afi, safi, type, mode);
     256           0 :             continue;
     257             :         }
     258             :       /* ORF Type and afi/safi error checks */
     259             :       /* capcode versus type */
     260          18 :       switch (hdr->code)
     261             :         {
     262             :           case CAPABILITY_CODE_ORF:
     263          17 :             switch (type)
     264             :               {
     265             :                 case ORF_TYPE_PREFIX:
     266           7 :                   break;
     267             :                 default:
     268          10 :                   bgp_capability_orf_not_support (peer, afi, safi, type, mode);
     269          10 :                   continue;
     270             :               }
     271           7 :             break;
     272             :           case CAPABILITY_CODE_ORF_OLD:
     273           1 :             switch (type)
     274             :               {
     275             :                 case ORF_TYPE_PREFIX_OLD:
     276           1 :                   break;
     277             :                 default:
     278           0 :                   bgp_capability_orf_not_support (peer, afi, safi, type, mode);
     279           0 :                   continue;
     280             :               }
     281           1 :             break;
     282             :           default:
     283           0 :             bgp_capability_orf_not_support (peer, afi, safi, type, mode);
     284           0 :             continue;
     285             :         }
     286             :                 
     287             :       /* AFI vs SAFI */
     288           8 :       if (!((afi == AFI_IP && safi == SAFI_UNICAST)
     289           0 :             || (afi == AFI_IP && safi == SAFI_MULTICAST)
     290           0 :             || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
     291             :         {
     292           0 :           bgp_capability_orf_not_support (peer, afi, safi, type, mode);
     293           0 :           continue;
     294             :         }
     295             :       
     296           8 :       if (BGP_DEBUG (normal, NORMAL))
     297          16 :         zlog_debug ("%s OPEN has %s ORF capability"
     298             :                     " as %s for afi/safi: %d/%d",
     299             :                     peer->host, LOOKUP (orf_type_str, type),
     300             :                     LOOKUP (orf_mode_str, mode),
     301           8 :                     entry.mpc.afi, safi);
     302             : 
     303           8 :       if (hdr->code == CAPABILITY_CODE_ORF)
     304             :         {
     305           7 :           sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
     306           7 :           rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
     307             :         }
     308           1 :       else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
     309             :         {
     310           1 :           sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
     311           1 :           rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
     312             :         }
     313             :       else
     314             :         {
     315           0 :           bgp_capability_orf_not_support (peer, afi, safi, type, mode);
     316           0 :           continue;
     317             :         }
     318             : 
     319           8 :       switch (mode)
     320             :         {
     321             :           case ORF_MODE_BOTH:
     322           8 :             SET_FLAG (peer->af_cap[afi][safi], sm_cap);
     323           8 :             SET_FLAG (peer->af_cap[afi][safi], rm_cap);
     324           8 :             break;
     325             :           case ORF_MODE_SEND:
     326           0 :             SET_FLAG (peer->af_cap[afi][safi], sm_cap);
     327           0 :             break;
     328             :           case ORF_MODE_RECEIVE:
     329           0 :             SET_FLAG (peer->af_cap[afi][safi], rm_cap);
     330           0 :             break;
     331             :         }
     332             :     }
     333           8 :   return 0;
     334             : }
     335             : 
     336             : static int
     337           2 : bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
     338             : {
     339           2 :   struct stream *s = BGP_INPUT (peer);
     340             :   u_int16_t restart_flag_time;
     341           2 :   int restart_bit = 0;
     342           2 :   size_t end = stream_get_getp (s) + caphdr->length;
     343             : 
     344           2 :   SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
     345           2 :   restart_flag_time = stream_getw(s);
     346           2 :   if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
     347           2 :     restart_bit = 1;
     348           2 :   UNSET_FLAG (restart_flag_time, 0xF000);
     349           2 :   peer->v_gr_restart = restart_flag_time;
     350             : 
     351           2 :   if (BGP_DEBUG (normal, NORMAL))
     352             :     {
     353           2 :       zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
     354           2 :       zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
     355             :                   peer->host, restart_bit ? " " : " not ",
     356             :                   peer->v_gr_restart);
     357             :     }
     358             : 
     359           9 :   while (stream_get_getp (s) + 4 <= end)
     360             :     {
     361           5 :       afi_t afi = stream_getw (s);
     362           5 :       safi_t safi = stream_getc (s);
     363           5 :       u_char flag = stream_getc (s);
     364             :       
     365           5 :       if (!bgp_afi_safi_valid_indices (afi, &safi))
     366             :         {
     367           0 :           if (BGP_DEBUG (normal, NORMAL))
     368           0 :             zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
     369             :                         " Ignore the Graceful Restart capability",
     370             :                         peer->host, afi, safi);
     371             :         }
     372           5 :       else if (!peer->afc[afi][safi])
     373             :         {
     374           0 :           if (BGP_DEBUG (normal, NORMAL))
     375           0 :             zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
     376             :                         " Ignore the Graceful Restart capability",
     377             :                         peer->host, afi, safi);
     378             :         }
     379             :       else
     380             :         {
     381           5 :           if (BGP_DEBUG (normal, NORMAL))
     382           5 :             zlog_debug ("%s Address family %s is%spreserved", peer->host,
     383             :                         afi_safi_print (afi, safi),
     384           5 :                         CHECK_FLAG (peer->af_cap[afi][safi],
     385             :                                     PEER_CAP_RESTART_AF_PRESERVE_RCV)
     386             :                         ? " " : " not ");
     387             : 
     388           5 :           SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
     389           5 :           if (CHECK_FLAG (flag, RESTART_F_BIT))
     390           0 :             SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
     391             :           
     392             :         }
     393             :     }
     394           2 :   return 0;
     395             : }
     396             : 
     397             : static as_t
     398          11 : bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
     399             : {
     400          11 :   SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
     401             :   
     402          11 :   if (hdr->length != CAPABILITY_CODE_AS4_LEN)
     403             :     {
     404           1 :       zlog_err ("%s AS4 capability has incorrect data length %d",
     405           1 :                 peer->host, hdr->length);
     406           1 :       return 0;
     407             :     }
     408             :   
     409          10 :   as_t as4 = stream_getl (BGP_INPUT(peer));
     410             :   
     411          10 :   if (BGP_DEBUG (as4, AS4))
     412          10 :     zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
     413             :                 peer->host, as4);
     414          10 :   return as4;
     415             : }
     416             : 
     417             : static const struct message capcode_str[] =
     418             : {
     419             :   { CAPABILITY_CODE_MP,                 "MultiProtocol Extensions"    },
     420             :   { CAPABILITY_CODE_REFRESH,            "Route Refresh"                       },
     421             :   { CAPABILITY_CODE_ORF,                "Cooperative Route Filtering"         },
     422             :   { CAPABILITY_CODE_RESTART,            "Graceful Restart"            },
     423             :   { CAPABILITY_CODE_AS4,                "4-octet AS number"           },
     424             :   { CAPABILITY_CODE_DYNAMIC,            "Dynamic"                     },
     425             :   { CAPABILITY_CODE_REFRESH_OLD,        "Route Refresh (Old)"         },
     426             :   { CAPABILITY_CODE_ORF_OLD,            "ORF (Old)"                   },
     427             : };
     428             : static const int capcode_str_max = array_size(capcode_str);
     429             : 
     430             : /* Minimum sizes for length field of each cap (so not inc. the header) */
     431             : static const size_t cap_minsizes[] = 
     432             : {
     433             :   [CAPABILITY_CODE_MP]          = sizeof (struct capability_mp_data),
     434             :   [CAPABILITY_CODE_REFRESH]     = CAPABILITY_CODE_REFRESH_LEN,
     435             :   [CAPABILITY_CODE_ORF]         = sizeof (struct capability_orf_entry),
     436             :   [CAPABILITY_CODE_RESTART]     = sizeof (struct capability_gr),
     437             :   [CAPABILITY_CODE_AS4]         = CAPABILITY_CODE_AS4_LEN,
     438             :   [CAPABILITY_CODE_DYNAMIC]     = CAPABILITY_CODE_DYNAMIC_LEN,
     439             :   [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
     440             :   [CAPABILITY_CODE_ORF_OLD]     = sizeof (struct capability_orf_entry),
     441             : };
     442             : 
     443             : /**
     444             :  * Parse given capability.
     445             :  * XXX: This is reading into a stream, but not using stream API
     446             :  *
     447             :  * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol
     448             :  *                           capabilities were encountered.
     449             :  */
     450             : static int
     451          55 : bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
     452             :                       u_char **error)
     453             : {
     454             :   int ret;
     455          55 :   struct stream *s = BGP_INPUT (peer);
     456          55 :   size_t end = stream_get_getp (s) + length;
     457             :   
     458          55 :   assert (STREAM_READABLE (s) >= length);
     459             :   
     460         165 :   while (stream_get_getp (s) < end)
     461             :     {
     462             :       size_t start;
     463          67 :       u_char *sp = stream_pnt (s);
     464             :       struct capability_header caphdr;
     465             :       
     466             :       /* We need at least capability code and capability length. */
     467          67 :       if (stream_get_getp(s) + 2 > end)
     468             :         {
     469           0 :           zlog_info ("%s Capability length error (< header)", peer->host);
     470           0 :           bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
     471          12 :           return -1;
     472             :         }
     473             :       
     474          67 :       caphdr.code = stream_getc (s);
     475          67 :       caphdr.length = stream_getc (s);
     476          67 :       start = stream_get_getp (s);
     477             :       
     478             :       /* Capability length check sanity check. */
     479          67 :       if (start + caphdr.length > end)
     480             :         {
     481           6 :           zlog_info ("%s Capability length error (< length)", peer->host);
     482           6 :           bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
     483           6 :           return -1;
     484             :         }
     485             :       
     486          61 :       if (BGP_DEBUG (normal, NORMAL))
     487         183 :         zlog_debug ("%s OPEN has %s capability (%u), length %u",
     488             :                    peer->host,
     489          61 :                    LOOKUP (capcode_str, caphdr.code),
     490         122 :                    caphdr.code, caphdr.length);
     491             :       
     492             :       /* Length sanity check, type-specific, for known capabilities */
     493          61 :       switch (caphdr.code)
     494             :         {
     495             :           case CAPABILITY_CODE_MP:
     496             :           case CAPABILITY_CODE_REFRESH:
     497             :           case CAPABILITY_CODE_REFRESH_OLD:
     498             :           case CAPABILITY_CODE_ORF:
     499             :           case CAPABILITY_CODE_ORF_OLD:
     500             :           case CAPABILITY_CODE_RESTART:
     501             :           case CAPABILITY_CODE_AS4:
     502             :           case CAPABILITY_CODE_DYNAMIC:
     503             :               /* Check length. */
     504          60 :               if (caphdr.length < cap_minsizes[caphdr.code])
     505             :                 {
     506          18 :                   zlog_info ("%s %s Capability length error: got %u,"
     507             :                              " expected at least %u",
     508             :                              peer->host, 
     509           6 :                              LOOKUP (capcode_str, caphdr.code),
     510           6 :                              caphdr.length, 
     511           6 :                              (unsigned) cap_minsizes[caphdr.code]);
     512           6 :                   bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
     513           6 :                   return -1;
     514             :                 }
     515             :           /* we deliberately ignore unknown codes, see below */
     516             :           default:
     517          55 :             break;
     518             :         }
     519             :       
     520          55 :       switch (caphdr.code)
     521             :         {
     522             :           case CAPABILITY_CODE_MP:
     523             :             {
     524          19 :               *mp_capability = 1;
     525             : 
     526             :               /* Ignore capability when override-capability is set. */
     527          19 :               if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
     528             :                 {
     529             :                   /* Set negotiated value. */
     530          19 :                   ret = bgp_capability_mp (peer, &caphdr);
     531             : 
     532             :                   /* Unsupported Capability. */
     533          19 :                   if (ret < 0)
     534             :                     {
     535             :                       /* Store return data. */
     536           1 :                       memcpy (*error, sp, caphdr.length + 2);
     537           1 :                       *error += caphdr.length + 2;
     538             :                     }
     539             :                 }
     540             :             }
     541          19 :             break;
     542             :           case CAPABILITY_CODE_REFRESH:
     543             :           case CAPABILITY_CODE_REFRESH_OLD:
     544             :             {
     545             :               /* BGP refresh capability */
     546          17 :               if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
     547           6 :                 SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
     548             :               else
     549          11 :                 SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
     550             :             }
     551          17 :             break;
     552             :           case CAPABILITY_CODE_ORF:
     553             :           case CAPABILITY_CODE_ORF_OLD:
     554           8 :             if (bgp_capability_orf_entry (peer, &caphdr))
     555           0 :               return -1;
     556           8 :             break;
     557             :           case CAPABILITY_CODE_RESTART:
     558           2 :             if (bgp_capability_restart (peer, &caphdr))
     559           0 :               return -1;
     560           2 :             break;
     561             :           case CAPABILITY_CODE_DYNAMIC:
     562           3 :             SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
     563           3 :             break;
     564             :           case CAPABILITY_CODE_AS4:
     565             :               /* Already handled as a special-case parsing of the capabilities
     566             :                * at the beginning of OPEN processing. So we care not a jot
     567             :                * for the value really, only error case.
     568             :                */
     569           5 :               if (!bgp_capability_as4 (peer, &caphdr))
     570           0 :                 return -1;
     571           5 :               break;            
     572             :           default:
     573           1 :             if (caphdr.code > 128)
     574             :               {
     575             :                 /* We don't send Notification for unknown vendor specific
     576             :                    capabilities.  It seems reasonable for now...  */
     577           0 :                 zlog_warn ("%s Vendor specific capability %d",
     578           0 :                            peer->host, caphdr.code);
     579             :               }
     580             :             else
     581             :               {
     582           1 :                 zlog_warn ("%s unrecognized capability code: %d - ignored",
     583           1 :                            peer->host, caphdr.code);
     584           1 :                 memcpy (*error, sp, caphdr.length + 2);
     585           1 :                 *error += caphdr.length + 2;
     586             :               }
     587             :           }
     588          55 :       if (stream_get_getp(s) != (start + caphdr.length))
     589             :         {
     590           8 :           if (stream_get_getp(s) > (start + caphdr.length))
     591           0 :             zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
     592           0 :                        peer->host, LOOKUP (capcode_str, caphdr.code),
     593           0 :                        caphdr.length);
     594           8 :           stream_set_getp (s, start + caphdr.length);
     595             :         }
     596             :     }
     597          43 :   return 0;
     598             : }
     599             : 
     600             : static int
     601           0 : bgp_auth_parse (struct peer *peer, size_t length)
     602             : {
     603           0 :   bgp_notify_send (peer, 
     604             :                    BGP_NOTIFY_OPEN_ERR, 
     605             :                    BGP_NOTIFY_OPEN_AUTH_FAILURE); 
     606           0 :   return -1;
     607             : }
     608             : 
     609             : static int
     610           0 : strict_capability_same (struct peer *peer)
     611             : {
     612             :   int i, j;
     613             : 
     614           0 :   for (i = AFI_IP; i < AFI_MAX; i++)
     615           0 :     for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
     616           0 :       if (peer->afc[i][j] != peer->afc_nego[i][j])
     617           0 :         return 0;
     618           0 :   return 1;
     619             : }
     620             : 
     621             : /* peek into option, stores ASN to *as4 if the AS4 capability was found.
     622             :  * Returns  0 if no as4 found, as4cap value otherwise.
     623             :  */
     624             : as_t
     625          37 : peek_for_as4_capability (struct peer *peer, u_char length)
     626             : {
     627          37 :   struct stream *s = BGP_INPUT (peer);
     628          37 :   size_t orig_getp = stream_get_getp (s);
     629          37 :   size_t end = orig_getp + length;
     630          37 :   as_t as4 = 0;
     631             :   
     632             :   /* The full capability parser will better flag the error.. */
     633          37 :   if (STREAM_READABLE(s) < length)
     634           0 :     return 0;
     635             : 
     636          37 :   if (BGP_DEBUG (as4, AS4))
     637          37 :     zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
     638             :                 " peeking for as4",
     639             :                 peer->host, length);
     640             :   /* the error cases we DONT handle, we ONLY try to read as4 out of
     641             :    * correctly formatted options.
     642             :    */
     643         113 :   while (stream_get_getp(s) < end) 
     644             :     {
     645             :       u_char opt_type;
     646             :       u_char opt_length;
     647             :       
     648             :       /* Check the length. */
     649          52 :       if (stream_get_getp (s) + 2 > end)
     650           0 :         goto end;
     651             :       
     652             :       /* Fetch option type and length. */
     653          52 :       opt_type = stream_getc (s);
     654          52 :       opt_length = stream_getc (s);
     655             :       
     656             :       /* Option length check. */
     657          52 :       if (stream_get_getp (s) + opt_length > end)
     658           0 :         goto end;
     659             :       
     660          52 :       if (opt_type == BGP_OPEN_OPT_CAP)
     661             :         {
     662          52 :           unsigned long capd_start = stream_get_getp (s);
     663          52 :           unsigned long capd_end = capd_start + opt_length;
     664             :           
     665          52 :           assert (capd_end <= end);
     666             :           
     667         156 :           while (stream_get_getp (s) < capd_end)
     668             :             {
     669             :               struct capability_header hdr;
     670             :               
     671          65 :               if (stream_get_getp (s) + 2 > capd_end)
     672          13 :                 goto end;
     673             :               
     674          65 :               hdr.code = stream_getc (s);
     675          65 :               hdr.length = stream_getc (s);
     676             :               
     677          65 :               if ((stream_get_getp(s) +  hdr.length) > capd_end)
     678           7 :                 goto end;
     679             : 
     680          58 :               if (hdr.code == CAPABILITY_CODE_AS4)
     681             :                 {
     682           6 :                   if (BGP_DEBUG (as4, AS4))
     683           6 :                     zlog_info ("[AS4] found AS4 capability, about to parse");
     684           6 :                   as4 = bgp_capability_as4 (peer, &hdr);
     685             :                   
     686           6 :                   goto end;
     687             :                 }
     688          52 :               stream_forward_getp (s, hdr.length);
     689             :             }
     690             :         }
     691             :     }
     692             : 
     693             : end:
     694          37 :   stream_set_getp (s, orig_getp);
     695          37 :   return as4;
     696             : }
     697             : 
     698             : /**
     699             :  * Parse open option.
     700             :  *
     701             :  * @param[out] mp_capability @see bgp_capability_parse() for semantics.
     702             :  */
     703             : int
     704          37 : bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
     705             : {
     706             :   int ret;
     707             :   u_char *error;
     708             :   u_char error_data[BGP_MAX_PACKET_SIZE];
     709          37 :   struct stream *s = BGP_INPUT(peer);
     710          37 :   size_t end = stream_get_getp (s) + length;
     711             : 
     712          37 :   ret = 0;
     713          37 :   error = error_data;
     714             : 
     715          37 :   if (BGP_DEBUG (normal, NORMAL))
     716          37 :     zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
     717             :                peer->host, length);
     718             :   
     719         117 :   while (stream_get_getp(s) < end)
     720             :     {
     721             :       u_char opt_type;
     722             :       u_char opt_length;
     723             :       
     724             :       /* Must have at least an OPEN option header */
     725          55 :       if (STREAM_READABLE(s) < 2)
     726             :         {
     727           0 :           zlog_info ("%s Option length error", peer->host);
     728           0 :           bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
     729           0 :           return -1;
     730             :         }
     731             : 
     732             :       /* Fetch option type and length. */
     733          55 :       opt_type = stream_getc (s);
     734          55 :       opt_length = stream_getc (s);
     735             :       
     736             :       /* Option length check. */
     737          55 :       if (STREAM_READABLE (s) < opt_length)
     738             :         {
     739           0 :           zlog_info ("%s Option length error", peer->host);
     740           0 :           bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
     741           0 :           return -1;
     742             :         }
     743             : 
     744          55 :       if (BGP_DEBUG (normal, NORMAL))
     745         110 :         zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
     746             :                    peer->host, opt_type,
     747             :                    opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
     748          55 :                    opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
     749             :                    opt_length);
     750             :   
     751          55 :       switch (opt_type)
     752             :         {
     753             :         case BGP_OPEN_OPT_AUTH:
     754           0 :           ret = bgp_auth_parse (peer, opt_length);
     755           0 :           break;
     756             :         case BGP_OPEN_OPT_CAP:
     757          55 :           ret = bgp_capability_parse (peer, opt_length, mp_capability, &error);
     758          55 :           break;
     759             :         default:
     760           0 :           bgp_notify_send (peer, 
     761             :                            BGP_NOTIFY_OPEN_ERR, 
     762             :                            BGP_NOTIFY_OPEN_UNSUP_PARAM); 
     763           0 :           ret = -1;
     764           0 :           break;
     765             :         }
     766             : 
     767             :       /* Parse error.  To accumulate all unsupported capability codes,
     768             :          bgp_capability_parse does not return -1 when encounter
     769             :          unsupported capability code.  To detect that, please check
     770             :          error and erro_data pointer, like below.  */
     771          55 :       if (ret < 0)
     772          12 :         return -1;
     773             :     }
     774             : 
     775             :   /* All OPEN option is parsed.  Check capability when strict compare
     776             :      flag is enabled.*/
     777          25 :   if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
     778             :     {
     779             :       /* If Unsupported Capability exists. */
     780           0 :       if (error != error_data)
     781             :         {
     782           0 :           bgp_notify_send_with_data (peer, 
     783             :                                      BGP_NOTIFY_OPEN_ERR, 
     784             :                                      BGP_NOTIFY_OPEN_UNSUP_CAPBL, 
     785           0 :                                      error_data, error - error_data);
     786           0 :           return -1;
     787             :         }
     788             : 
     789             :       /* Check local capability does not negotiated with remote
     790             :          peer. */
     791           0 :       if (! strict_capability_same (peer))
     792             :         {
     793           0 :           bgp_notify_send (peer, 
     794             :                            BGP_NOTIFY_OPEN_ERR, 
     795             :                            BGP_NOTIFY_OPEN_UNSUP_CAPBL);
     796           0 :           return -1;
     797             :         }
     798             :     }
     799             : 
     800             :   /* Check there are no common AFI/SAFIs and send Unsupported Capability
     801             :      error. */
     802          38 :   if (*mp_capability &&
     803          13 :       ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
     804             :     {
     805          13 :       if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] 
     806           0 :           && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
     807           0 :           && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
     808           0 :           && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
     809           0 :           && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
     810             :         {
     811           0 :           plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not "
     812             :                     "overlap with received MP capabilities",
     813             :                     peer->host);
     814             : 
     815           0 :           if (error != error_data)
     816             : 
     817           0 :             bgp_notify_send_with_data (peer, 
     818             :                                        BGP_NOTIFY_OPEN_ERR, 
     819             :                                        BGP_NOTIFY_OPEN_UNSUP_CAPBL, 
     820           0 :                                        error_data, error - error_data);
     821             :           else
     822           0 :             bgp_notify_send (peer, 
     823             :                              BGP_NOTIFY_OPEN_ERR, 
     824             :                              BGP_NOTIFY_OPEN_UNSUP_CAPBL);
     825           0 :           return -1;
     826             :         }
     827             :     }
     828          25 :   return 0;
     829             : }
     830             : 
     831             : static void
     832           0 : bgp_open_capability_orf (struct stream *s, struct peer *peer,
     833             :                          afi_t afi, safi_t safi, u_char code)
     834             : {
     835             :   u_char cap_len;
     836             :   u_char orf_len;
     837             :   unsigned long capp;
     838             :   unsigned long orfp;
     839             :   unsigned long numberp;
     840           0 :   int number_of_orfs = 0;
     841             : 
     842           0 :   if (safi == SAFI_MPLS_VPN)
     843           0 :     safi = SAFI_MPLS_LABELED_VPN;
     844             : 
     845           0 :   stream_putc (s, BGP_OPEN_OPT_CAP);
     846           0 :   capp = stream_get_endp (s);           /* Set Capability Len Pointer */
     847           0 :   stream_putc (s, 0);                   /* Capability Length */
     848           0 :   stream_putc (s, code);                /* Capability Code */
     849           0 :   orfp = stream_get_endp (s);           /* Set ORF Len Pointer */
     850           0 :   stream_putc (s, 0);                   /* ORF Length */
     851           0 :   stream_putw (s, afi);
     852           0 :   stream_putc (s, 0);
     853           0 :   stream_putc (s, safi);
     854           0 :   numberp = stream_get_endp (s);        /* Set Number Pointer */
     855           0 :   stream_putc (s, 0);                   /* Number of ORFs */
     856             : 
     857             :   /* Address Prefix ORF */
     858           0 :   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
     859           0 :       || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
     860             :     {
     861           0 :       stream_putc (s, (code == CAPABILITY_CODE_ORF ?
     862             :                    ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
     863             : 
     864           0 :       if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
     865           0 :           && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
     866             :         {
     867           0 :           SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
     868           0 :           SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
     869           0 :           stream_putc (s, ORF_MODE_BOTH);
     870             :         }
     871           0 :       else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
     872             :         {
     873           0 :           SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
     874           0 :           stream_putc (s, ORF_MODE_SEND);
     875             :         }
     876             :       else
     877             :         {
     878           0 :           SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
     879           0 :           stream_putc (s, ORF_MODE_RECEIVE);
     880             :         }
     881           0 :       number_of_orfs++;
     882             :     }
     883             : 
     884             :   /* Total Number of ORFs. */
     885           0 :   stream_putc_at (s, numberp, number_of_orfs);
     886             : 
     887             :   /* Total ORF Len. */
     888           0 :   orf_len = stream_get_endp (s) - orfp - 1;
     889           0 :   stream_putc_at (s, orfp, orf_len);
     890             : 
     891             :   /* Total Capability Len. */
     892           0 :   cap_len = stream_get_endp (s) - capp - 1;
     893           0 :   stream_putc_at (s, capp, cap_len);
     894           0 : }
     895             : 
     896             : /* Fill in capability open option to the packet. */
     897             : void
     898           0 : bgp_open_capability (struct stream *s, struct peer *peer)
     899             : {
     900             :   u_char len;
     901             :   unsigned long cp;
     902             :   afi_t afi;
     903             :   safi_t safi;
     904             :   as_t local_as;
     905             : 
     906             :   /* Remember current pointer for Opt Parm Len. */
     907           0 :   cp = stream_get_endp (s);
     908             : 
     909             :   /* Opt Parm Len. */
     910           0 :   stream_putc (s, 0);
     911             : 
     912             :   /* Do not send capability. */
     913           0 :   if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN) 
     914           0 :       || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
     915           0 :     return;
     916             : 
     917             :   /* IPv4 unicast. */
     918           0 :   if (peer->afc[AFI_IP][SAFI_UNICAST])
     919             :     {
     920           0 :       peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1;
     921           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
     922           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
     923           0 :       stream_putc (s, CAPABILITY_CODE_MP);
     924           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN);
     925           0 :       stream_putw (s, AFI_IP);
     926           0 :       stream_putc (s, 0);
     927           0 :       stream_putc (s, SAFI_UNICAST);
     928             :     }
     929             :   /* IPv4 multicast. */
     930           0 :   if (peer->afc[AFI_IP][SAFI_MULTICAST])
     931             :     {
     932           0 :       peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1;
     933           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
     934           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
     935           0 :       stream_putc (s, CAPABILITY_CODE_MP);
     936           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN);
     937           0 :       stream_putw (s, AFI_IP);
     938           0 :       stream_putc (s, 0);
     939           0 :       stream_putc (s, SAFI_MULTICAST);
     940             :     }
     941             :   /* IPv4 VPN */
     942           0 :   if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
     943             :     {
     944           0 :       peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
     945           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
     946           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
     947           0 :       stream_putc (s, CAPABILITY_CODE_MP);
     948           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN);
     949           0 :       stream_putw (s, AFI_IP);
     950           0 :       stream_putc (s, 0);
     951           0 :       stream_putc (s, SAFI_MPLS_LABELED_VPN);
     952             :     }
     953             : #ifdef HAVE_IPV6
     954             :   /* IPv6 unicast. */
     955           0 :   if (peer->afc[AFI_IP6][SAFI_UNICAST])
     956             :     {
     957           0 :       peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1;
     958           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
     959           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
     960           0 :       stream_putc (s, CAPABILITY_CODE_MP);
     961           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN);
     962           0 :       stream_putw (s, AFI_IP6);
     963           0 :       stream_putc (s, 0);
     964           0 :       stream_putc (s, SAFI_UNICAST);
     965             :     }
     966             :   /* IPv6 multicast. */
     967           0 :   if (peer->afc[AFI_IP6][SAFI_MULTICAST])
     968             :     {
     969           0 :       peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
     970           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
     971           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
     972           0 :       stream_putc (s, CAPABILITY_CODE_MP);
     973           0 :       stream_putc (s, CAPABILITY_CODE_MP_LEN);
     974           0 :       stream_putw (s, AFI_IP6);
     975           0 :       stream_putc (s, 0);
     976           0 :       stream_putc (s, SAFI_MULTICAST);
     977             :     }
     978             : #endif /* HAVE_IPV6 */
     979             : 
     980             :   /* Route refresh. */
     981           0 :   SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
     982           0 :   stream_putc (s, BGP_OPEN_OPT_CAP);
     983           0 :   stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
     984           0 :   stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
     985           0 :   stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
     986           0 :   stream_putc (s, BGP_OPEN_OPT_CAP);
     987           0 :   stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
     988           0 :   stream_putc (s, CAPABILITY_CODE_REFRESH);
     989           0 :   stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
     990             : 
     991             :   /* AS4 */
     992           0 :   SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
     993           0 :   stream_putc (s, BGP_OPEN_OPT_CAP);
     994           0 :   stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
     995           0 :   stream_putc (s, CAPABILITY_CODE_AS4);
     996           0 :   stream_putc (s, CAPABILITY_CODE_AS4_LEN);
     997           0 :   if ( peer->change_local_as )
     998           0 :     local_as = peer->change_local_as;
     999             :   else
    1000           0 :     local_as = peer->local_as;
    1001           0 :   stream_putl (s, local_as );
    1002             : 
    1003             :   /* ORF capability. */
    1004           0 :   for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
    1005           0 :     for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
    1006           0 :       if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
    1007           0 :           || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
    1008             :         {
    1009           0 :           bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
    1010           0 :           bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
    1011             :         }
    1012             : 
    1013             :   /* Dynamic capability. */
    1014           0 :   if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
    1015             :     {
    1016           0 :       SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
    1017           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
    1018           0 :       stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
    1019           0 :       stream_putc (s, CAPABILITY_CODE_DYNAMIC);
    1020           0 :       stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
    1021             :     }
    1022             : 
    1023             :   /* Graceful restart capability */
    1024           0 :   if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
    1025             :     {
    1026           0 :       SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV);
    1027           0 :       stream_putc (s, BGP_OPEN_OPT_CAP);
    1028           0 :       stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2);
    1029           0 :       stream_putc (s, CAPABILITY_CODE_RESTART);
    1030           0 :       stream_putc (s, CAPABILITY_CODE_RESTART_LEN);
    1031           0 :       stream_putw (s, peer->bgp->restart_time);
    1032             :      }
    1033             : 
    1034             :   /* Total Opt Parm Len. */
    1035           0 :   len = stream_get_endp (s) - cp - 1;
    1036           0 :   stream_putc_at (s, cp, len);
    1037             : }

Generated by: LCOV version 1.10