blob: 82deb3d05af027491ee10df7fde1ac6123af3370 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP open message handling
2 Copyright (C) 1998, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-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"
Paul Jakma6d582722007-08-06 15:21:45 +000029#include "memory.h"
paul718e3742002-12-13 20:15:29 +000030
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"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000037#include "bgpd/bgp_aspath.h"
hasso538621f2004-05-21 09:31:30 +000038#include "bgpd/bgp_vty.h"
39
paul718e3742002-12-13 20:15:29 +000040/* 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
50void
51bgp_capability_vty_out (struct vty *vty, struct peer *peer)
52{
paul5228ad22004-06-04 17:58:18 +000053 char *pnt;
54 char *end;
Paul Jakma6d582722007-08-06 15:21:45 +000055 struct capability_mp_data mpc;
56 struct capability_header *hdr;
paul718e3742002-12-13 20:15:29 +000057
58 pnt = peer->notify.data;
59 end = pnt + peer->notify.length;
Paul Jakma6d582722007-08-06 15:21:45 +000060
paul718e3742002-12-13 20:15:29 +000061 while (pnt < end)
62 {
Paul Jakma6d582722007-08-06 15:21:45 +000063 if (pnt + sizeof (struct capability_mp_data) + 2 > end)
paul718e3742002-12-13 20:15:29 +000064 return;
Paul Jakma6d582722007-08-06 15:21:45 +000065
66 hdr = (struct capability_header *)pnt;
67 if (pnt + hdr->length + 2 > end)
paul718e3742002-12-13 20:15:29 +000068 return;
69
Paul Jakma6d582722007-08-06 15:21:45 +000070 memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data));
71
72 if (hdr->code == CAPABILITY_CODE_MP)
paul718e3742002-12-13 20:15:29 +000073 {
74 vty_out (vty, " Capability error for: Multi protocol ");
75
Paul Jakma6d582722007-08-06 15:21:45 +000076 switch (ntohs (mpc.afi))
paul718e3742002-12-13 20:15:29 +000077 {
78 case AFI_IP:
79 vty_out (vty, "AFI IPv4, ");
80 break;
81 case AFI_IP6:
82 vty_out (vty, "AFI IPv6, ");
83 break;
84 default:
Paul Jakma6d582722007-08-06 15:21:45 +000085 vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
paul718e3742002-12-13 20:15:29 +000086 break;
87 }
Paul Jakma6d582722007-08-06 15:21:45 +000088 switch (mpc.safi)
paul718e3742002-12-13 20:15:29 +000089 {
90 case SAFI_UNICAST:
91 vty_out (vty, "SAFI Unicast");
92 break;
93 case SAFI_MULTICAST:
94 vty_out (vty, "SAFI Multicast");
95 break;
Denis Ovsienkoe81537d2011-07-14 12:36:19 +040096 case SAFI_MPLS_LABELED_VPN:
97 vty_out (vty, "SAFI MPLS-labeled VPN");
paul718e3742002-12-13 20:15:29 +000098 break;
99 default:
Paul Jakma6d582722007-08-06 15:21:45 +0000100 vty_out (vty, "SAFI Unknown %d ", mpc.safi);
paul718e3742002-12-13 20:15:29 +0000101 break;
102 }
103 vty_out (vty, "%s", VTY_NEWLINE);
104 }
Paul Jakma6d582722007-08-06 15:21:45 +0000105 else if (hdr->code >= 128)
paul718e3742002-12-13 20:15:29 +0000106 vty_out (vty, " Capability error: vendor specific capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000107 hdr->code);
paul718e3742002-12-13 20:15:29 +0000108 else
109 vty_out (vty, " Capability error: unknown capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000110 hdr->code);
paul718e3742002-12-13 20:15:29 +0000111
Paul Jakma6d582722007-08-06 15:21:45 +0000112 pnt += hdr->length + 2;
paul718e3742002-12-13 20:15:29 +0000113 }
114}
115
Paul Jakma6d582722007-08-06 15:21:45 +0000116static void
117bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
118{
119 mpc->afi = stream_getw (s);
120 mpc->reserved = stream_getc (s);
121 mpc->safi = stream_getc (s);
122}
123
124int
125bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
126{
Paul Jakma6d582722007-08-06 15:21:45 +0000127 switch (afi)
128 {
129 case AFI_IP:
130#ifdef HAVE_IPV6
131 case AFI_IP6:
132#endif
133 switch (*safi)
134 {
Denis Ovsienkoe81537d2011-07-14 12:36:19 +0400135 /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */
136 case SAFI_MPLS_LABELED_VPN:
Paul Jakma6d582722007-08-06 15:21:45 +0000137 *safi = SAFI_MPLS_VPN;
138 case SAFI_UNICAST:
139 case SAFI_MULTICAST:
140 case SAFI_MPLS_VPN:
141 return 1;
142 }
143 }
144 zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
145
146 return 0;
147}
148
paul718e3742002-12-13 20:15:29 +0000149/* Set negotiated capability value. */
paul94f2b392005-06-28 12:44:16 +0000150static int
Paul Jakma6d582722007-08-06 15:21:45 +0000151bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
paul718e3742002-12-13 20:15:29 +0000152{
Paul Jakma6d582722007-08-06 15:21:45 +0000153 struct capability_mp_data mpc;
154 struct stream *s = BGP_INPUT (peer);
155
156 bgp_capability_mp_data (s, &mpc);
157
158 if (BGP_DEBUG (normal, NORMAL))
159 zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
160 peer->host, mpc.afi, mpc.safi);
161
162 if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
163 return -1;
164
165 /* Now safi remapped, and afi/safi are valid array indices */
166 peer->afc_recv[mpc.afi][mpc.safi] = 1;
167
168 if (peer->afc[mpc.afi][mpc.safi])
Paul Jakmae08286b2007-09-18 12:11:26 +0000169 peer->afc_nego[mpc.afi][mpc.safi] = 1;
Paul Jakma6d582722007-08-06 15:21:45 +0000170 else
171 return -1;
paul718e3742002-12-13 20:15:29 +0000172
173 return 0;
174}
175
paul94f2b392005-06-28 12:44:16 +0000176static void
paul718e3742002-12-13 20:15:29 +0000177bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
178 u_char type, u_char mode)
179{
180 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000181 zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
paul718e3742002-12-13 20:15:29 +0000182 peer->host, afi, safi, type, mode);
183}
184
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700185static const struct message orf_type_str[] =
paul718e3742002-12-13 20:15:29 +0000186{
Paul Jakma6d582722007-08-06 15:21:45 +0000187 { ORF_TYPE_PREFIX, "Prefixlist" },
188 { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" },
189};
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700190static const int orf_type_str_max
191 = sizeof(orf_type_str)/sizeof(orf_type_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000192
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700193static const struct message orf_mode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000194{
195 { ORF_MODE_RECEIVE, "Receive" },
196 { ORF_MODE_SEND, "Send" },
197 { ORF_MODE_BOTH, "Both" },
198};
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700199static const int orf_mode_str_max
200 = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000201
202static int
203bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
204{
205 struct stream *s = BGP_INPUT (peer);
206 struct capability_orf_entry entry;
207 afi_t afi;
208 safi_t safi;
paul718e3742002-12-13 20:15:29 +0000209 u_char type;
210 u_char mode;
211 u_int16_t sm_cap = 0; /* capability send-mode receive */
212 u_int16_t rm_cap = 0; /* capability receive-mode receive */
213 int i;
214
Paul Jakma6d582722007-08-06 15:21:45 +0000215 /* ORF Entry header */
216 bgp_capability_mp_data (s, &entry.mpc);
217 entry.num = stream_getc (s);
218 afi = entry.mpc.afi;
219 safi = entry.mpc.safi;
220
paul718e3742002-12-13 20:15:29 +0000221 if (BGP_DEBUG (normal, NORMAL))
Paul Jakma6d582722007-08-06 15:21:45 +0000222 zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
223 peer->host, entry.mpc.afi, entry.mpc.safi);
paul718e3742002-12-13 20:15:29 +0000224
225 /* Check AFI and SAFI. */
Paul Jakma6d582722007-08-06 15:21:45 +0000226 if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
paul718e3742002-12-13 20:15:29 +0000227 {
Paul Jakma6d582722007-08-06 15:21:45 +0000228 zlog_info ("%s Addr-family %d/%d not supported."
229 " Ignoring the ORF capability",
230 peer->host, entry.mpc.afi, entry.mpc.safi);
231 return 0;
232 }
233
234 /* validate number field */
235 if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
236 {
237 zlog_info ("%s ORF Capability entry length error,"
238 " Cap length %u, num %u",
239 peer->host, hdr->length, entry.num);
240 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
paul718e3742002-12-13 20:15:29 +0000241 return -1;
242 }
243
Paul Jakma6d582722007-08-06 15:21:45 +0000244 for (i = 0 ; i < entry.num ; i++)
paul718e3742002-12-13 20:15:29 +0000245 {
Paul Jakma6d582722007-08-06 15:21:45 +0000246 type = stream_getc(s);
247 mode = stream_getc(s);
248
paul718e3742002-12-13 20:15:29 +0000249 /* ORF Mode error check */
Paul Jakma6d582722007-08-06 15:21:45 +0000250 switch (mode)
251 {
252 case ORF_MODE_BOTH:
253 case ORF_MODE_SEND:
254 case ORF_MODE_RECEIVE:
255 break;
256 default:
257 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
258 continue;
paul718e3742002-12-13 20:15:29 +0000259 }
Paul Jakma6d582722007-08-06 15:21:45 +0000260 /* ORF Type and afi/safi error checks */
261 /* capcode versus type */
262 switch (hdr->code)
263 {
264 case CAPABILITY_CODE_ORF:
265 switch (type)
266 {
267 case ORF_TYPE_PREFIX:
268 break;
269 default:
270 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
271 continue;
272 }
273 break;
274 case CAPABILITY_CODE_ORF_OLD:
275 switch (type)
276 {
277 case ORF_TYPE_PREFIX_OLD:
278 break;
279 default:
280 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
281 continue;
282 }
283 break;
284 default:
285 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
286 continue;
287 }
288
289 /* AFI vs SAFI */
290 if (!((afi == AFI_IP && safi == SAFI_UNICAST)
291 || (afi == AFI_IP && safi == SAFI_MULTICAST)
292 || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
293 {
294 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
295 continue;
296 }
297
298 if (BGP_DEBUG (normal, NORMAL))
299 zlog_debug ("%s OPEN has %s ORF capability"
300 " as %s for afi/safi: %d/%d",
301 peer->host, LOOKUP (orf_type_str, type),
302 LOOKUP (orf_mode_str, mode),
303 entry.mpc.afi, safi);
paul718e3742002-12-13 20:15:29 +0000304
Paul Jakma6d582722007-08-06 15:21:45 +0000305 if (hdr->code == CAPABILITY_CODE_ORF)
paul718e3742002-12-13 20:15:29 +0000306 {
Paul Jakma6d582722007-08-06 15:21:45 +0000307 sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
308 rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
paul718e3742002-12-13 20:15:29 +0000309 }
Paul Jakma6d582722007-08-06 15:21:45 +0000310 else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
paul718e3742002-12-13 20:15:29 +0000311 {
Paul Jakma6d582722007-08-06 15:21:45 +0000312 sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
313 rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
paul718e3742002-12-13 20:15:29 +0000314 }
315 else
316 {
317 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
318 continue;
319 }
320
321 switch (mode)
322 {
323 case ORF_MODE_BOTH:
324 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
325 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
326 break;
327 case ORF_MODE_SEND:
328 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
329 break;
330 case ORF_MODE_RECEIVE:
331 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
332 break;
333 }
334 }
335 return 0;
336}
337
paul94f2b392005-06-28 12:44:16 +0000338static int
Paul Jakma6d582722007-08-06 15:21:45 +0000339bgp_capability_orf (struct peer *peer, struct capability_header *hdr)
340{
341 struct stream *s = BGP_INPUT (peer);
342 size_t end = stream_get_getp (s) + hdr->length;
343
344 assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
345
346 /* We must have at least one ORF entry, as the caller has already done
347 * minimum length validation for the capability code - for ORF there must
348 * at least one ORF entry (header and unknown number of pairs of bytes).
349 */
350 do
351 {
352 if (bgp_capability_orf_entry (peer, hdr) == -1)
353 return -1;
354 }
355 while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
356
357 return 0;
358}
359
360static int
361bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
362{
363 struct stream *s = BGP_INPUT (peer);
364 u_int16_t restart_flag_time;
365 int restart_bit = 0;
366 size_t end = stream_get_getp (s) + caphdr->length;
367
368 SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
369 restart_flag_time = stream_getw(s);
370 if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
371 restart_bit = 1;
372 UNSET_FLAG (restart_flag_time, 0xF000);
373 peer->v_gr_restart = restart_flag_time;
374
375 if (BGP_DEBUG (normal, NORMAL))
376 {
377 zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
378 zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
379 peer->host, restart_bit ? " " : " not ",
380 peer->v_gr_restart);
381 }
382
Peter Pentchev74ffab32011-09-12 16:30:31 +0400383 while (stream_get_getp (s) + 4 <= end)
Paul Jakma6d582722007-08-06 15:21:45 +0000384 {
385 afi_t afi = stream_getw (s);
386 safi_t safi = stream_getc (s);
387 u_char flag = stream_getc (s);
388
389 if (!bgp_afi_safi_valid_indices (afi, &safi))
390 {
391 if (BGP_DEBUG (normal, NORMAL))
392 zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
393 " Ignore the Graceful Restart capability",
394 peer->host, afi, safi);
395 }
396 else if (!peer->afc[afi][safi])
397 {
398 if (BGP_DEBUG (normal, NORMAL))
399 zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
400 " Ignore the Graceful Restart capability",
401 peer->host, afi, safi);
402 }
403 else
404 {
405 if (BGP_DEBUG (normal, NORMAL))
406 zlog_debug ("%s Address family %s is%spreserved", peer->host,
407 afi_safi_print (afi, safi),
408 CHECK_FLAG (peer->af_cap[afi][safi],
409 PEER_CAP_RESTART_AF_PRESERVE_RCV)
410 ? " " : " not ");
411
412 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
413 if (CHECK_FLAG (flag, RESTART_F_BIT))
414 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
415
416 }
417 }
418 return 0;
419}
420
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000421static as_t
422bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
423{
424 as_t as4 = stream_getl (BGP_INPUT(peer));
425
426 if (BGP_DEBUG (as4, AS4))
427 zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
428 peer->host, as4);
429 SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
430
431 return as4;
432}
433
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700434static const struct message capcode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000435{
Paul Jakma6d582722007-08-06 15:21:45 +0000436 { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
437 { CAPABILITY_CODE_REFRESH, "Route Refresh" },
438 { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" },
439 { CAPABILITY_CODE_RESTART, "Graceful Restart" },
440 { CAPABILITY_CODE_AS4, "4-octet AS number" },
441 { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
442 { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
443 { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
444};
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700445static const int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000446
447/* Minimum sizes for length field of each cap (so not inc. the header) */
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700448static const size_t cap_minsizes[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000449{
450 [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data),
451 [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
452 [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry),
Paul Jakma370b64a2007-12-22 16:49:52 +0000453 [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr),
Paul Jakma6d582722007-08-06 15:21:45 +0000454 [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
455 [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
456 [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
457 [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
458};
459
460/* Parse given capability.
461 * XXX: This is reading into a stream, but not using stream API
462 */
463static int
464bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
paul718e3742002-12-13 20:15:29 +0000465{
466 int ret;
Paul Jakma6d582722007-08-06 15:21:45 +0000467 struct stream *s = BGP_INPUT (peer);
468 size_t end = stream_get_getp (s) + length;
469
470 assert (STREAM_READABLE (s) >= length);
471
472 while (stream_get_getp (s) < end)
paul718e3742002-12-13 20:15:29 +0000473 {
Paul Jakma6d582722007-08-06 15:21:45 +0000474 size_t start;
475 u_char *sp = stream_pnt (s);
476 struct capability_header caphdr;
477
paul718e3742002-12-13 20:15:29 +0000478 /* We need at least capability code and capability length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000479 if (stream_get_getp(s) + 2 > end)
paul718e3742002-12-13 20:15:29 +0000480 {
Paul Jakma6d582722007-08-06 15:21:45 +0000481 zlog_info ("%s Capability length error (< header)", peer->host);
paul718e3742002-12-13 20:15:29 +0000482 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
483 return -1;
484 }
Paul Jakma6d582722007-08-06 15:21:45 +0000485
486 caphdr.code = stream_getc (s);
487 caphdr.length = stream_getc (s);
488 start = stream_get_getp (s);
489
490 /* Capability length check sanity check. */
491 if (start + caphdr.length > end)
paul718e3742002-12-13 20:15:29 +0000492 {
Paul Jakma6d582722007-08-06 15:21:45 +0000493 zlog_info ("%s Capability length error (< length)", peer->host);
paul718e3742002-12-13 20:15:29 +0000494 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
495 return -1;
496 }
Paul Jakma6d582722007-08-06 15:21:45 +0000497
498 if (BGP_DEBUG (normal, NORMAL))
499 zlog_debug ("%s OPEN has %s capability (%u), length %u",
500 peer->host,
501 LOOKUP (capcode_str, caphdr.code),
502 caphdr.code, caphdr.length);
503
504 /* Length sanity check, type-specific, for known capabilities */
505 switch (caphdr.code)
506 {
507 case CAPABILITY_CODE_MP:
508 case CAPABILITY_CODE_REFRESH:
509 case CAPABILITY_CODE_REFRESH_OLD:
510 case CAPABILITY_CODE_ORF:
511 case CAPABILITY_CODE_ORF_OLD:
512 case CAPABILITY_CODE_RESTART:
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000513 case CAPABILITY_CODE_AS4:
Paul Jakma6d582722007-08-06 15:21:45 +0000514 case CAPABILITY_CODE_DYNAMIC:
515 /* Check length. */
516 if (caphdr.length < cap_minsizes[caphdr.code])
517 {
518 zlog_info ("%s %s Capability length error: got %u,"
519 " expected at least %u",
520 peer->host,
521 LOOKUP (capcode_str, caphdr.code),
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700522 caphdr.length,
523 (unsigned) cap_minsizes[caphdr.code]);
Paul Jakma6d582722007-08-06 15:21:45 +0000524 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
525 return -1;
526 }
527 /* we deliberately ignore unknown codes, see below */
528 default:
529 break;
530 }
531
532 switch (caphdr.code)
533 {
534 case CAPABILITY_CODE_MP:
535 {
536 /* Ignore capability when override-capability is set. */
537 if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
538 {
539 /* Set negotiated value. */
540 ret = bgp_capability_mp (peer, &caphdr);
paul718e3742002-12-13 20:15:29 +0000541
Paul Jakma6d582722007-08-06 15:21:45 +0000542 /* Unsupported Capability. */
543 if (ret < 0)
544 {
545 /* Store return data. */
546 memcpy (*error, sp, caphdr.length + 2);
547 *error += caphdr.length + 2;
548 }
549 }
550 }
551 break;
552 case CAPABILITY_CODE_REFRESH:
553 case CAPABILITY_CODE_REFRESH_OLD:
554 {
555 /* BGP refresh capability */
556 if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
557 SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
558 else
559 SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
560 }
561 break;
562 case CAPABILITY_CODE_ORF:
563 case CAPABILITY_CODE_ORF_OLD:
564 if (bgp_capability_orf (peer, &caphdr))
565 return -1;
566 break;
567 case CAPABILITY_CODE_RESTART:
568 if (bgp_capability_restart (peer, &caphdr))
569 return -1;
570 break;
571 case CAPABILITY_CODE_DYNAMIC:
572 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
573 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000574 case CAPABILITY_CODE_AS4:
575 /* Already handled as a special-case parsing of the capabilities
576 * at the beginning of OPEN processing. So we care not a jot
577 * for the value really, only error case.
578 */
579 if (!bgp_capability_as4 (peer, &caphdr))
580 return -1;
581 break;
Paul Jakma6d582722007-08-06 15:21:45 +0000582 default:
583 if (caphdr.code > 128)
584 {
585 /* We don't send Notification for unknown vendor specific
586 capabilities. It seems reasonable for now... */
587 zlog_warn ("%s Vendor specific capability %d",
588 peer->host, caphdr.code);
589 }
590 else
591 {
592 zlog_warn ("%s unrecognized capability code: %d - ignored",
593 peer->host, caphdr.code);
594 memcpy (*error, sp, caphdr.length + 2);
595 *error += caphdr.length + 2;
596 }
597 }
598 if (stream_get_getp(s) != (start + caphdr.length))
599 {
600 if (stream_get_getp(s) > (start + caphdr.length))
601 zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
602 peer->host, LOOKUP (capcode_str, caphdr.code),
603 caphdr.length);
604 stream_set_getp (s, start + caphdr.length);
605 }
paul718e3742002-12-13 20:15:29 +0000606 }
607 return 0;
608}
609
paul94f2b392005-06-28 12:44:16 +0000610static int
Paul Jakma6d582722007-08-06 15:21:45 +0000611bgp_auth_parse (struct peer *peer, size_t length)
paul718e3742002-12-13 20:15:29 +0000612{
613 bgp_notify_send (peer,
614 BGP_NOTIFY_OPEN_ERR,
615 BGP_NOTIFY_OPEN_AUTH_FAILURE);
616 return -1;
617}
618
paul94f2b392005-06-28 12:44:16 +0000619static int
paul718e3742002-12-13 20:15:29 +0000620strict_capability_same (struct peer *peer)
621{
622 int i, j;
623
624 for (i = AFI_IP; i < AFI_MAX; i++)
625 for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
626 if (peer->afc[i][j] != peer->afc_nego[i][j])
627 return 0;
628 return 1;
629}
630
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000631/* peek into option, stores ASN to *as4 if the AS4 capability was found.
632 * Returns 0 if no as4 found, as4cap value otherwise.
633 */
634as_t
635peek_for_as4_capability (struct peer *peer, u_char length)
636{
637 struct stream *s = BGP_INPUT (peer);
638 size_t orig_getp = stream_get_getp (s);
639 size_t end = orig_getp + length;
640 as_t as4 = 0;
641
642 /* The full capability parser will better flag the error.. */
643 if (STREAM_READABLE(s) < length)
644 return 0;
645
646 if (BGP_DEBUG (as4, AS4))
647 zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
648 " peeking for as4",
649 peer->host, length);
650 /* the error cases we DONT handle, we ONLY try to read as4 out of
651 * correctly formatted options.
652 */
653 while (stream_get_getp(s) < end)
654 {
655 u_char opt_type;
656 u_char opt_length;
657
658 /* Check the length. */
659 if (stream_get_getp (s) + 2 > end)
660 goto end;
661
662 /* Fetch option type and length. */
663 opt_type = stream_getc (s);
664 opt_length = stream_getc (s);
665
666 /* Option length check. */
667 if (stream_get_getp (s) + opt_length > end)
668 goto end;
669
670 if (opt_type == BGP_OPEN_OPT_CAP)
671 {
672 unsigned long capd_start = stream_get_getp (s);
673 unsigned long capd_end = capd_start + opt_length;
674
675 assert (capd_end <= end);
676
677 while (stream_get_getp (s) < capd_end)
678 {
679 struct capability_header hdr;
680
681 if (stream_get_getp (s) + 2 > capd_end)
682 goto end;
683
684 hdr.code = stream_getc (s);
685 hdr.length = stream_getc (s);
686
687 if ((stream_get_getp(s) + hdr.length) > capd_end)
688 goto end;
689
690 if (hdr.code == CAPABILITY_CODE_AS4)
691 {
692 if (hdr.length != CAPABILITY_CODE_AS4_LEN)
693 goto end;
694
695 if (BGP_DEBUG (as4, AS4))
696 zlog_info ("[AS4] found AS4 capability, about to parse");
697 as4 = bgp_capability_as4 (peer, &hdr);
698
699 goto end;
700 }
701 stream_forward_getp (s, hdr.length);
702 }
703 }
704 }
705
706end:
707 stream_set_getp (s, orig_getp);
708 return as4;
709}
710
paul718e3742002-12-13 20:15:29 +0000711/* Parse open option */
712int
713bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
714{
715 int ret;
paul718e3742002-12-13 20:15:29 +0000716 u_char *error;
717 u_char error_data[BGP_MAX_PACKET_SIZE];
Paul Jakma6d582722007-08-06 15:21:45 +0000718 struct stream *s = BGP_INPUT(peer);
719 size_t end = stream_get_getp (s) + length;
paul718e3742002-12-13 20:15:29 +0000720
721 ret = 0;
paul718e3742002-12-13 20:15:29 +0000722 error = error_data;
723
724 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000725 zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
paul718e3742002-12-13 20:15:29 +0000726 peer->host, length);
727
Paul Jakma6d582722007-08-06 15:21:45 +0000728 while (stream_get_getp(s) < end)
paul718e3742002-12-13 20:15:29 +0000729 {
Paul Jakma6d582722007-08-06 15:21:45 +0000730 u_char opt_type;
731 u_char opt_length;
732
733 /* Must have at least an OPEN option header */
734 if (STREAM_READABLE(s) < 2)
paul718e3742002-12-13 20:15:29 +0000735 {
736 zlog_info ("%s Option length error", peer->host);
737 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
738 return -1;
739 }
740
741 /* Fetch option type and length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000742 opt_type = stream_getc (s);
743 opt_length = stream_getc (s);
paul718e3742002-12-13 20:15:29 +0000744
745 /* Option length check. */
Paul Jakma6d582722007-08-06 15:21:45 +0000746 if (STREAM_READABLE (s) < opt_length)
paul718e3742002-12-13 20:15:29 +0000747 {
748 zlog_info ("%s Option length error", peer->host);
749 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
750 return -1;
751 }
752
753 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000754 zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
paul718e3742002-12-13 20:15:29 +0000755 peer->host, opt_type,
756 opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
757 opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
758 opt_length);
759
760 switch (opt_type)
761 {
762 case BGP_OPEN_OPT_AUTH:
Paul Jakma6d582722007-08-06 15:21:45 +0000763 ret = bgp_auth_parse (peer, opt_length);
paul718e3742002-12-13 20:15:29 +0000764 break;
765 case BGP_OPEN_OPT_CAP:
Paul Jakma6d582722007-08-06 15:21:45 +0000766 ret = bgp_capability_parse (peer, opt_length, &error);
paul718e3742002-12-13 20:15:29 +0000767 *capability = 1;
768 break;
769 default:
770 bgp_notify_send (peer,
771 BGP_NOTIFY_OPEN_ERR,
772 BGP_NOTIFY_OPEN_UNSUP_PARAM);
773 ret = -1;
774 break;
775 }
776
777 /* Parse error. To accumulate all unsupported capability codes,
778 bgp_capability_parse does not return -1 when encounter
779 unsupported capability code. To detect that, please check
780 error and erro_data pointer, like below. */
781 if (ret < 0)
782 return -1;
paul718e3742002-12-13 20:15:29 +0000783 }
784
785 /* All OPEN option is parsed. Check capability when strict compare
786 flag is enabled.*/
787 if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
788 {
789 /* If Unsupported Capability exists. */
790 if (error != error_data)
791 {
792 bgp_notify_send_with_data (peer,
793 BGP_NOTIFY_OPEN_ERR,
794 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
795 error_data, error - error_data);
796 return -1;
797 }
798
799 /* Check local capability does not negotiated with remote
800 peer. */
801 if (! strict_capability_same (peer))
802 {
803 bgp_notify_send (peer,
804 BGP_NOTIFY_OPEN_ERR,
805 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
806 return -1;
807 }
808 }
809
810 /* Check there is no common capability send Unsupported Capability
811 error. */
812 if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
813 {
814 if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
815 && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
816 && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
817 && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
818 && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
819 {
820 plog_err (peer->log, "%s [Error] No common capability", peer->host);
821
822 if (error != error_data)
823
824 bgp_notify_send_with_data (peer,
825 BGP_NOTIFY_OPEN_ERR,
826 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
827 error_data, error - error_data);
828 else
829 bgp_notify_send (peer,
830 BGP_NOTIFY_OPEN_ERR,
831 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
832 return -1;
833 }
834 }
835 return 0;
836}
837
paul94f2b392005-06-28 12:44:16 +0000838static void
paul718e3742002-12-13 20:15:29 +0000839bgp_open_capability_orf (struct stream *s, struct peer *peer,
840 afi_t afi, safi_t safi, u_char code)
841{
842 u_char cap_len;
843 u_char orf_len;
844 unsigned long capp;
845 unsigned long orfp;
846 unsigned long numberp;
847 int number_of_orfs = 0;
848
849 if (safi == SAFI_MPLS_VPN)
Denis Ovsienkoe81537d2011-07-14 12:36:19 +0400850 safi = SAFI_MPLS_LABELED_VPN;
paul718e3742002-12-13 20:15:29 +0000851
852 stream_putc (s, BGP_OPEN_OPT_CAP);
paul9985f832005-02-09 15:51:56 +0000853 capp = stream_get_endp (s); /* Set Capability Len Pointer */
paul718e3742002-12-13 20:15:29 +0000854 stream_putc (s, 0); /* Capability Length */
855 stream_putc (s, code); /* Capability Code */
paul9985f832005-02-09 15:51:56 +0000856 orfp = stream_get_endp (s); /* Set ORF Len Pointer */
paul718e3742002-12-13 20:15:29 +0000857 stream_putc (s, 0); /* ORF Length */
858 stream_putw (s, afi);
859 stream_putc (s, 0);
860 stream_putc (s, safi);
paul9985f832005-02-09 15:51:56 +0000861 numberp = stream_get_endp (s); /* Set Number Pointer */
paul718e3742002-12-13 20:15:29 +0000862 stream_putc (s, 0); /* Number of ORFs */
863
864 /* Address Prefix ORF */
865 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
866 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
867 {
868 stream_putc (s, (code == CAPABILITY_CODE_ORF ?
869 ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
870
871 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
872 && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
873 {
874 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
875 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
876 stream_putc (s, ORF_MODE_BOTH);
877 }
878 else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
879 {
880 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
881 stream_putc (s, ORF_MODE_SEND);
882 }
883 else
884 {
885 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
886 stream_putc (s, ORF_MODE_RECEIVE);
887 }
888 number_of_orfs++;
889 }
890
891 /* Total Number of ORFs. */
892 stream_putc_at (s, numberp, number_of_orfs);
893
894 /* Total ORF Len. */
paul9985f832005-02-09 15:51:56 +0000895 orf_len = stream_get_endp (s) - orfp - 1;
paul718e3742002-12-13 20:15:29 +0000896 stream_putc_at (s, orfp, orf_len);
897
898 /* Total Capability Len. */
paul9985f832005-02-09 15:51:56 +0000899 cap_len = stream_get_endp (s) - capp - 1;
paul718e3742002-12-13 20:15:29 +0000900 stream_putc_at (s, capp, cap_len);
901}
902
903/* Fill in capability open option to the packet. */
904void
905bgp_open_capability (struct stream *s, struct peer *peer)
906{
907 u_char len;
908 unsigned long cp;
909 afi_t afi;
910 safi_t safi;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000911 as_t local_as;
paul718e3742002-12-13 20:15:29 +0000912
913 /* Remember current pointer for Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +0000914 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +0000915
916 /* Opt Parm Len. */
917 stream_putc (s, 0);
918
919 /* Do not send capability. */
920 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
921 || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
922 return;
923
paul718e3742002-12-13 20:15:29 +0000924 /* IPv4 unicast. */
925 if (peer->afc[AFI_IP][SAFI_UNICAST])
926 {
927 peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1;
928 stream_putc (s, BGP_OPEN_OPT_CAP);
929 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
930 stream_putc (s, CAPABILITY_CODE_MP);
931 stream_putc (s, CAPABILITY_CODE_MP_LEN);
932 stream_putw (s, AFI_IP);
933 stream_putc (s, 0);
934 stream_putc (s, SAFI_UNICAST);
935 }
936 /* IPv4 multicast. */
937 if (peer->afc[AFI_IP][SAFI_MULTICAST])
938 {
939 peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1;
940 stream_putc (s, BGP_OPEN_OPT_CAP);
941 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
942 stream_putc (s, CAPABILITY_CODE_MP);
943 stream_putc (s, CAPABILITY_CODE_MP_LEN);
944 stream_putw (s, AFI_IP);
945 stream_putc (s, 0);
946 stream_putc (s, SAFI_MULTICAST);
947 }
948 /* IPv4 VPN */
949 if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
950 {
951 peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
952 stream_putc (s, BGP_OPEN_OPT_CAP);
953 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
954 stream_putc (s, CAPABILITY_CODE_MP);
955 stream_putc (s, CAPABILITY_CODE_MP_LEN);
956 stream_putw (s, AFI_IP);
957 stream_putc (s, 0);
Denis Ovsienkoe81537d2011-07-14 12:36:19 +0400958 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +0000959 }
960#ifdef HAVE_IPV6
961 /* IPv6 unicast. */
962 if (peer->afc[AFI_IP6][SAFI_UNICAST])
963 {
964 peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1;
965 stream_putc (s, BGP_OPEN_OPT_CAP);
966 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
967 stream_putc (s, CAPABILITY_CODE_MP);
968 stream_putc (s, CAPABILITY_CODE_MP_LEN);
969 stream_putw (s, AFI_IP6);
970 stream_putc (s, 0);
971 stream_putc (s, SAFI_UNICAST);
972 }
973 /* IPv6 multicast. */
974 if (peer->afc[AFI_IP6][SAFI_MULTICAST])
975 {
976 peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
977 stream_putc (s, BGP_OPEN_OPT_CAP);
978 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
979 stream_putc (s, CAPABILITY_CODE_MP);
980 stream_putc (s, CAPABILITY_CODE_MP_LEN);
981 stream_putw (s, AFI_IP6);
982 stream_putc (s, 0);
983 stream_putc (s, SAFI_MULTICAST);
984 }
985#endif /* HAVE_IPV6 */
986
987 /* Route refresh. */
hassoc9502432005-02-01 22:01:48 +0000988 SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
989 stream_putc (s, BGP_OPEN_OPT_CAP);
990 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
991 stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
992 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
993 stream_putc (s, BGP_OPEN_OPT_CAP);
994 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
995 stream_putc (s, CAPABILITY_CODE_REFRESH);
996 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
paul718e3742002-12-13 20:15:29 +0000997
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000998 /* AS4 */
999 SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
1000 stream_putc (s, BGP_OPEN_OPT_CAP);
1001 stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
1002 stream_putc (s, CAPABILITY_CODE_AS4);
1003 stream_putc (s, CAPABILITY_CODE_AS4_LEN);
1004 if ( peer->change_local_as )
1005 local_as = peer->change_local_as;
1006 else
1007 local_as = peer->local_as;
1008 stream_putl (s, local_as );
1009
paul718e3742002-12-13 20:15:29 +00001010 /* ORF capability. */
1011 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
1012 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
1013 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
1014 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
1015 {
1016 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
1017 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
1018 }
1019
1020 /* Dynamic capability. */
1021 if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
1022 {
1023 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
1024 stream_putc (s, BGP_OPEN_OPT_CAP);
1025 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
1026 stream_putc (s, CAPABILITY_CODE_DYNAMIC);
1027 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
1028 }
1029
hasso538621f2004-05-21 09:31:30 +00001030 /* Graceful restart capability */
1031 if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
1032 {
1033 SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV);
1034 stream_putc (s, BGP_OPEN_OPT_CAP);
1035 stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2);
1036 stream_putc (s, CAPABILITY_CODE_RESTART);
1037 stream_putc (s, CAPABILITY_CODE_RESTART_LEN);
1038 stream_putw (s, peer->bgp->restart_time);
1039 }
1040
paul718e3742002-12-13 20:15:29 +00001041 /* Total Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +00001042 len = stream_get_endp (s) - cp - 1;
paul718e3742002-12-13 20:15:29 +00001043 stream_putc_at (s, cp, len);
1044}