blob: 37595817e9a243f7959841e13d7a995c79ac93db [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;
96 case SAFI_UNICAST_MULTICAST:
97 vty_out (vty, "SAFI Unicast Multicast");
98 break;
99 case BGP_SAFI_VPNV4:
100 vty_out (vty, "SAFI MPLS-VPN");
101 break;
102 default:
Paul Jakma6d582722007-08-06 15:21:45 +0000103 vty_out (vty, "SAFI Unknown %d ", mpc.safi);
paul718e3742002-12-13 20:15:29 +0000104 break;
105 }
106 vty_out (vty, "%s", VTY_NEWLINE);
107 }
Paul Jakma6d582722007-08-06 15:21:45 +0000108 else if (hdr->code >= 128)
paul718e3742002-12-13 20:15:29 +0000109 vty_out (vty, " Capability error: vendor specific capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000110 hdr->code);
paul718e3742002-12-13 20:15:29 +0000111 else
112 vty_out (vty, " Capability error: unknown capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000113 hdr->code);
paul718e3742002-12-13 20:15:29 +0000114
Paul Jakma6d582722007-08-06 15:21:45 +0000115 pnt += hdr->length + 2;
paul718e3742002-12-13 20:15:29 +0000116 }
117}
118
Paul Jakma6d582722007-08-06 15:21:45 +0000119static void
120bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
121{
122 mpc->afi = stream_getw (s);
123 mpc->reserved = stream_getc (s);
124 mpc->safi = stream_getc (s);
125}
126
127int
128bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
129{
130 /* VPNvX are AFI specific */
131 if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4)
132 || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6))
133 {
134 zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi);
135 return 0;
136 }
137
138 switch (afi)
139 {
140 case AFI_IP:
141#ifdef HAVE_IPV6
142 case AFI_IP6:
143#endif
144 switch (*safi)
145 {
146 /* BGP VPNvX SAFI isn't contigious with others, remap */
147 case BGP_SAFI_VPNV4:
148 case BGP_SAFI_VPNV6:
149 *safi = SAFI_MPLS_VPN;
150 case SAFI_UNICAST:
151 case SAFI_MULTICAST:
152 case SAFI_MPLS_VPN:
153 return 1;
154 }
155 }
156 zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
157
158 return 0;
159}
160
paul718e3742002-12-13 20:15:29 +0000161/* Set negotiated capability value. */
paul94f2b392005-06-28 12:44:16 +0000162static int
Paul Jakma6d582722007-08-06 15:21:45 +0000163bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
paul718e3742002-12-13 20:15:29 +0000164{
Paul Jakma6d582722007-08-06 15:21:45 +0000165 struct capability_mp_data mpc;
166 struct stream *s = BGP_INPUT (peer);
167
168 bgp_capability_mp_data (s, &mpc);
169
170 if (BGP_DEBUG (normal, NORMAL))
171 zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
172 peer->host, mpc.afi, mpc.safi);
173
174 if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
175 return -1;
176
177 /* Now safi remapped, and afi/safi are valid array indices */
178 peer->afc_recv[mpc.afi][mpc.safi] = 1;
179
180 if (peer->afc[mpc.afi][mpc.safi])
Paul Jakmae08286b2007-09-18 12:11:26 +0000181 peer->afc_nego[mpc.afi][mpc.safi] = 1;
Paul Jakma6d582722007-08-06 15:21:45 +0000182 else
183 return -1;
paul718e3742002-12-13 20:15:29 +0000184
185 return 0;
186}
187
paul94f2b392005-06-28 12:44:16 +0000188static void
paul718e3742002-12-13 20:15:29 +0000189bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
190 u_char type, u_char mode)
191{
192 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000193 zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
paul718e3742002-12-13 20:15:29 +0000194 peer->host, afi, safi, type, mode);
195}
196
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700197static const struct message orf_type_str[] =
paul718e3742002-12-13 20:15:29 +0000198{
Paul Jakma6d582722007-08-06 15:21:45 +0000199 { ORF_TYPE_PREFIX, "Prefixlist" },
200 { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" },
201};
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700202static const int orf_type_str_max
203 = sizeof(orf_type_str)/sizeof(orf_type_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000204
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700205static const struct message orf_mode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000206{
207 { ORF_MODE_RECEIVE, "Receive" },
208 { ORF_MODE_SEND, "Send" },
209 { ORF_MODE_BOTH, "Both" },
210};
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700211static const int orf_mode_str_max
212 = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000213
214static int
215bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
216{
217 struct stream *s = BGP_INPUT (peer);
218 struct capability_orf_entry entry;
219 afi_t afi;
220 safi_t safi;
paul718e3742002-12-13 20:15:29 +0000221 u_char type;
222 u_char mode;
223 u_int16_t sm_cap = 0; /* capability send-mode receive */
224 u_int16_t rm_cap = 0; /* capability receive-mode receive */
225 int i;
226
Paul Jakma6d582722007-08-06 15:21:45 +0000227 /* ORF Entry header */
228 bgp_capability_mp_data (s, &entry.mpc);
229 entry.num = stream_getc (s);
230 afi = entry.mpc.afi;
231 safi = entry.mpc.safi;
232
paul718e3742002-12-13 20:15:29 +0000233 if (BGP_DEBUG (normal, NORMAL))
Paul Jakma6d582722007-08-06 15:21:45 +0000234 zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
235 peer->host, entry.mpc.afi, entry.mpc.safi);
paul718e3742002-12-13 20:15:29 +0000236
237 /* Check AFI and SAFI. */
Paul Jakma6d582722007-08-06 15:21:45 +0000238 if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
paul718e3742002-12-13 20:15:29 +0000239 {
Paul Jakma6d582722007-08-06 15:21:45 +0000240 zlog_info ("%s Addr-family %d/%d not supported."
241 " Ignoring the ORF capability",
242 peer->host, entry.mpc.afi, entry.mpc.safi);
243 return 0;
244 }
245
246 /* validate number field */
247 if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
248 {
249 zlog_info ("%s ORF Capability entry length error,"
250 " Cap length %u, num %u",
251 peer->host, hdr->length, entry.num);
252 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
paul718e3742002-12-13 20:15:29 +0000253 return -1;
254 }
255
Paul Jakma6d582722007-08-06 15:21:45 +0000256 for (i = 0 ; i < entry.num ; i++)
paul718e3742002-12-13 20:15:29 +0000257 {
Paul Jakma6d582722007-08-06 15:21:45 +0000258 type = stream_getc(s);
259 mode = stream_getc(s);
260
paul718e3742002-12-13 20:15:29 +0000261 /* ORF Mode error check */
Paul Jakma6d582722007-08-06 15:21:45 +0000262 switch (mode)
263 {
264 case ORF_MODE_BOTH:
265 case ORF_MODE_SEND:
266 case ORF_MODE_RECEIVE:
267 break;
268 default:
269 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
270 continue;
paul718e3742002-12-13 20:15:29 +0000271 }
Paul Jakma6d582722007-08-06 15:21:45 +0000272 /* ORF Type and afi/safi error checks */
273 /* capcode versus type */
274 switch (hdr->code)
275 {
276 case CAPABILITY_CODE_ORF:
277 switch (type)
278 {
279 case ORF_TYPE_PREFIX:
280 break;
281 default:
282 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
283 continue;
284 }
285 break;
286 case CAPABILITY_CODE_ORF_OLD:
287 switch (type)
288 {
289 case ORF_TYPE_PREFIX_OLD:
290 break;
291 default:
292 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
293 continue;
294 }
295 break;
296 default:
297 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
298 continue;
299 }
300
301 /* AFI vs SAFI */
302 if (!((afi == AFI_IP && safi == SAFI_UNICAST)
303 || (afi == AFI_IP && safi == SAFI_MULTICAST)
304 || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
305 {
306 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
307 continue;
308 }
309
310 if (BGP_DEBUG (normal, NORMAL))
311 zlog_debug ("%s OPEN has %s ORF capability"
312 " as %s for afi/safi: %d/%d",
313 peer->host, LOOKUP (orf_type_str, type),
314 LOOKUP (orf_mode_str, mode),
315 entry.mpc.afi, safi);
paul718e3742002-12-13 20:15:29 +0000316
Paul Jakma6d582722007-08-06 15:21:45 +0000317 if (hdr->code == CAPABILITY_CODE_ORF)
paul718e3742002-12-13 20:15:29 +0000318 {
Paul Jakma6d582722007-08-06 15:21:45 +0000319 sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
320 rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
paul718e3742002-12-13 20:15:29 +0000321 }
Paul Jakma6d582722007-08-06 15:21:45 +0000322 else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
paul718e3742002-12-13 20:15:29 +0000323 {
Paul Jakma6d582722007-08-06 15:21:45 +0000324 sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
325 rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
paul718e3742002-12-13 20:15:29 +0000326 }
327 else
328 {
329 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
330 continue;
331 }
332
333 switch (mode)
334 {
335 case ORF_MODE_BOTH:
336 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
337 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
338 break;
339 case ORF_MODE_SEND:
340 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
341 break;
342 case ORF_MODE_RECEIVE:
343 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
344 break;
345 }
346 }
347 return 0;
348}
349
paul94f2b392005-06-28 12:44:16 +0000350static int
Paul Jakma6d582722007-08-06 15:21:45 +0000351bgp_capability_orf (struct peer *peer, struct capability_header *hdr)
352{
353 struct stream *s = BGP_INPUT (peer);
354 size_t end = stream_get_getp (s) + hdr->length;
355
356 assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
357
358 /* We must have at least one ORF entry, as the caller has already done
359 * minimum length validation for the capability code - for ORF there must
360 * at least one ORF entry (header and unknown number of pairs of bytes).
361 */
362 do
363 {
364 if (bgp_capability_orf_entry (peer, hdr) == -1)
365 return -1;
366 }
367 while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
368
369 return 0;
370}
371
372static int
373bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
374{
375 struct stream *s = BGP_INPUT (peer);
376 u_int16_t restart_flag_time;
377 int restart_bit = 0;
378 size_t end = stream_get_getp (s) + caphdr->length;
379
380 SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
381 restart_flag_time = stream_getw(s);
382 if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
383 restart_bit = 1;
384 UNSET_FLAG (restart_flag_time, 0xF000);
385 peer->v_gr_restart = restart_flag_time;
386
387 if (BGP_DEBUG (normal, NORMAL))
388 {
389 zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
390 zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
391 peer->host, restart_bit ? " " : " not ",
392 peer->v_gr_restart);
393 }
394
395 while (stream_get_getp (s) + 4 < end)
396 {
397 afi_t afi = stream_getw (s);
398 safi_t safi = stream_getc (s);
399 u_char flag = stream_getc (s);
400
401 if (!bgp_afi_safi_valid_indices (afi, &safi))
402 {
403 if (BGP_DEBUG (normal, NORMAL))
404 zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
405 " Ignore the Graceful Restart capability",
406 peer->host, afi, safi);
407 }
408 else if (!peer->afc[afi][safi])
409 {
410 if (BGP_DEBUG (normal, NORMAL))
411 zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
412 " Ignore the Graceful Restart capability",
413 peer->host, afi, safi);
414 }
415 else
416 {
417 if (BGP_DEBUG (normal, NORMAL))
418 zlog_debug ("%s Address family %s is%spreserved", peer->host,
419 afi_safi_print (afi, safi),
420 CHECK_FLAG (peer->af_cap[afi][safi],
421 PEER_CAP_RESTART_AF_PRESERVE_RCV)
422 ? " " : " not ");
423
424 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
425 if (CHECK_FLAG (flag, RESTART_F_BIT))
426 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
427
428 }
429 }
430 return 0;
431}
432
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000433static as_t
434bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
435{
436 as_t as4 = stream_getl (BGP_INPUT(peer));
437
438 if (BGP_DEBUG (as4, AS4))
439 zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
440 peer->host, as4);
441 SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
442
443 return as4;
444}
445
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700446static const struct message capcode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000447{
Paul Jakma6d582722007-08-06 15:21:45 +0000448 { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
449 { CAPABILITY_CODE_REFRESH, "Route Refresh" },
450 { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" },
451 { CAPABILITY_CODE_RESTART, "Graceful Restart" },
452 { CAPABILITY_CODE_AS4, "4-octet AS number" },
453 { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
454 { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
455 { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
456};
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700457static const int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000458
459/* Minimum sizes for length field of each cap (so not inc. the header) */
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700460static const size_t cap_minsizes[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000461{
462 [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data),
463 [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
464 [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry),
Paul Jakma370b64a2007-12-22 16:49:52 +0000465 [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr),
Paul Jakma6d582722007-08-06 15:21:45 +0000466 [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
467 [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
468 [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
469 [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
470};
471
472/* Parse given capability.
473 * XXX: This is reading into a stream, but not using stream API
474 */
475static int
476bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
paul718e3742002-12-13 20:15:29 +0000477{
478 int ret;
Paul Jakma6d582722007-08-06 15:21:45 +0000479 struct stream *s = BGP_INPUT (peer);
480 size_t end = stream_get_getp (s) + length;
481
482 assert (STREAM_READABLE (s) >= length);
483
484 while (stream_get_getp (s) < end)
paul718e3742002-12-13 20:15:29 +0000485 {
Paul Jakma6d582722007-08-06 15:21:45 +0000486 size_t start;
487 u_char *sp = stream_pnt (s);
488 struct capability_header caphdr;
489
paul718e3742002-12-13 20:15:29 +0000490 /* We need at least capability code and capability length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000491 if (stream_get_getp(s) + 2 > end)
paul718e3742002-12-13 20:15:29 +0000492 {
Paul Jakma6d582722007-08-06 15:21:45 +0000493 zlog_info ("%s Capability length error (< header)", 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 caphdr.code = stream_getc (s);
499 caphdr.length = stream_getc (s);
500 start = stream_get_getp (s);
501
502 /* Capability length check sanity check. */
503 if (start + caphdr.length > end)
paul718e3742002-12-13 20:15:29 +0000504 {
Paul Jakma6d582722007-08-06 15:21:45 +0000505 zlog_info ("%s Capability length error (< length)", peer->host);
paul718e3742002-12-13 20:15:29 +0000506 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
507 return -1;
508 }
Paul Jakma6d582722007-08-06 15:21:45 +0000509
510 if (BGP_DEBUG (normal, NORMAL))
511 zlog_debug ("%s OPEN has %s capability (%u), length %u",
512 peer->host,
513 LOOKUP (capcode_str, caphdr.code),
514 caphdr.code, caphdr.length);
515
516 /* Length sanity check, type-specific, for known capabilities */
517 switch (caphdr.code)
518 {
519 case CAPABILITY_CODE_MP:
520 case CAPABILITY_CODE_REFRESH:
521 case CAPABILITY_CODE_REFRESH_OLD:
522 case CAPABILITY_CODE_ORF:
523 case CAPABILITY_CODE_ORF_OLD:
524 case CAPABILITY_CODE_RESTART:
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000525 case CAPABILITY_CODE_AS4:
Paul Jakma6d582722007-08-06 15:21:45 +0000526 case CAPABILITY_CODE_DYNAMIC:
527 /* Check length. */
528 if (caphdr.length < cap_minsizes[caphdr.code])
529 {
530 zlog_info ("%s %s Capability length error: got %u,"
531 " expected at least %u",
532 peer->host,
533 LOOKUP (capcode_str, caphdr.code),
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700534 caphdr.length,
535 (unsigned) cap_minsizes[caphdr.code]);
Paul Jakma6d582722007-08-06 15:21:45 +0000536 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
537 return -1;
538 }
539 /* we deliberately ignore unknown codes, see below */
540 default:
541 break;
542 }
543
544 switch (caphdr.code)
545 {
546 case CAPABILITY_CODE_MP:
547 {
548 /* Ignore capability when override-capability is set. */
549 if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
550 {
551 /* Set negotiated value. */
552 ret = bgp_capability_mp (peer, &caphdr);
paul718e3742002-12-13 20:15:29 +0000553
Paul Jakma6d582722007-08-06 15:21:45 +0000554 /* Unsupported Capability. */
555 if (ret < 0)
556 {
557 /* Store return data. */
558 memcpy (*error, sp, caphdr.length + 2);
559 *error += caphdr.length + 2;
560 }
561 }
562 }
563 break;
564 case CAPABILITY_CODE_REFRESH:
565 case CAPABILITY_CODE_REFRESH_OLD:
566 {
567 /* BGP refresh capability */
568 if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
569 SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
570 else
571 SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
572 }
573 break;
574 case CAPABILITY_CODE_ORF:
575 case CAPABILITY_CODE_ORF_OLD:
576 if (bgp_capability_orf (peer, &caphdr))
577 return -1;
578 break;
579 case CAPABILITY_CODE_RESTART:
580 if (bgp_capability_restart (peer, &caphdr))
581 return -1;
582 break;
583 case CAPABILITY_CODE_DYNAMIC:
584 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
585 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000586 case CAPABILITY_CODE_AS4:
587 /* Already handled as a special-case parsing of the capabilities
588 * at the beginning of OPEN processing. So we care not a jot
589 * for the value really, only error case.
590 */
591 if (!bgp_capability_as4 (peer, &caphdr))
592 return -1;
593 break;
Paul Jakma6d582722007-08-06 15:21:45 +0000594 default:
595 if (caphdr.code > 128)
596 {
597 /* We don't send Notification for unknown vendor specific
598 capabilities. It seems reasonable for now... */
599 zlog_warn ("%s Vendor specific capability %d",
600 peer->host, caphdr.code);
601 }
602 else
603 {
604 zlog_warn ("%s unrecognized capability code: %d - ignored",
605 peer->host, caphdr.code);
606 memcpy (*error, sp, caphdr.length + 2);
607 *error += caphdr.length + 2;
608 }
609 }
610 if (stream_get_getp(s) != (start + caphdr.length))
611 {
612 if (stream_get_getp(s) > (start + caphdr.length))
613 zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
614 peer->host, LOOKUP (capcode_str, caphdr.code),
615 caphdr.length);
616 stream_set_getp (s, start + caphdr.length);
617 }
paul718e3742002-12-13 20:15:29 +0000618 }
619 return 0;
620}
621
paul94f2b392005-06-28 12:44:16 +0000622static int
Paul Jakma6d582722007-08-06 15:21:45 +0000623bgp_auth_parse (struct peer *peer, size_t length)
paul718e3742002-12-13 20:15:29 +0000624{
625 bgp_notify_send (peer,
626 BGP_NOTIFY_OPEN_ERR,
627 BGP_NOTIFY_OPEN_AUTH_FAILURE);
628 return -1;
629}
630
paul94f2b392005-06-28 12:44:16 +0000631static int
paul718e3742002-12-13 20:15:29 +0000632strict_capability_same (struct peer *peer)
633{
634 int i, j;
635
636 for (i = AFI_IP; i < AFI_MAX; i++)
637 for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
638 if (peer->afc[i][j] != peer->afc_nego[i][j])
639 return 0;
640 return 1;
641}
642
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000643/* peek into option, stores ASN to *as4 if the AS4 capability was found.
644 * Returns 0 if no as4 found, as4cap value otherwise.
645 */
646as_t
647peek_for_as4_capability (struct peer *peer, u_char length)
648{
649 struct stream *s = BGP_INPUT (peer);
650 size_t orig_getp = stream_get_getp (s);
651 size_t end = orig_getp + length;
652 as_t as4 = 0;
653
654 /* The full capability parser will better flag the error.. */
655 if (STREAM_READABLE(s) < length)
656 return 0;
657
658 if (BGP_DEBUG (as4, AS4))
659 zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
660 " peeking for as4",
661 peer->host, length);
662 /* the error cases we DONT handle, we ONLY try to read as4 out of
663 * correctly formatted options.
664 */
665 while (stream_get_getp(s) < end)
666 {
667 u_char opt_type;
668 u_char opt_length;
669
670 /* Check the length. */
671 if (stream_get_getp (s) + 2 > end)
672 goto end;
673
674 /* Fetch option type and length. */
675 opt_type = stream_getc (s);
676 opt_length = stream_getc (s);
677
678 /* Option length check. */
679 if (stream_get_getp (s) + opt_length > end)
680 goto end;
681
682 if (opt_type == BGP_OPEN_OPT_CAP)
683 {
684 unsigned long capd_start = stream_get_getp (s);
685 unsigned long capd_end = capd_start + opt_length;
686
687 assert (capd_end <= end);
688
689 while (stream_get_getp (s) < capd_end)
690 {
691 struct capability_header hdr;
692
693 if (stream_get_getp (s) + 2 > capd_end)
694 goto end;
695
696 hdr.code = stream_getc (s);
697 hdr.length = stream_getc (s);
698
699 if ((stream_get_getp(s) + hdr.length) > capd_end)
700 goto end;
701
702 if (hdr.code == CAPABILITY_CODE_AS4)
703 {
704 if (hdr.length != CAPABILITY_CODE_AS4_LEN)
705 goto end;
706
707 if (BGP_DEBUG (as4, AS4))
708 zlog_info ("[AS4] found AS4 capability, about to parse");
709 as4 = bgp_capability_as4 (peer, &hdr);
710
711 goto end;
712 }
713 stream_forward_getp (s, hdr.length);
714 }
715 }
716 }
717
718end:
719 stream_set_getp (s, orig_getp);
720 return as4;
721}
722
paul718e3742002-12-13 20:15:29 +0000723/* Parse open option */
724int
725bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
726{
727 int ret;
paul718e3742002-12-13 20:15:29 +0000728 u_char *error;
729 u_char error_data[BGP_MAX_PACKET_SIZE];
Paul Jakma6d582722007-08-06 15:21:45 +0000730 struct stream *s = BGP_INPUT(peer);
731 size_t end = stream_get_getp (s) + length;
paul718e3742002-12-13 20:15:29 +0000732
733 ret = 0;
paul718e3742002-12-13 20:15:29 +0000734 error = error_data;
735
736 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000737 zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
paul718e3742002-12-13 20:15:29 +0000738 peer->host, length);
739
Paul Jakma6d582722007-08-06 15:21:45 +0000740 while (stream_get_getp(s) < end)
paul718e3742002-12-13 20:15:29 +0000741 {
Paul Jakma6d582722007-08-06 15:21:45 +0000742 u_char opt_type;
743 u_char opt_length;
744
745 /* Must have at least an OPEN option header */
746 if (STREAM_READABLE(s) < 2)
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 /* Fetch option type and length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000754 opt_type = stream_getc (s);
755 opt_length = stream_getc (s);
paul718e3742002-12-13 20:15:29 +0000756
757 /* Option length check. */
Paul Jakma6d582722007-08-06 15:21:45 +0000758 if (STREAM_READABLE (s) < opt_length)
paul718e3742002-12-13 20:15:29 +0000759 {
760 zlog_info ("%s Option length error", peer->host);
761 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
762 return -1;
763 }
764
765 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000766 zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
paul718e3742002-12-13 20:15:29 +0000767 peer->host, opt_type,
768 opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
769 opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
770 opt_length);
771
772 switch (opt_type)
773 {
774 case BGP_OPEN_OPT_AUTH:
Paul Jakma6d582722007-08-06 15:21:45 +0000775 ret = bgp_auth_parse (peer, opt_length);
paul718e3742002-12-13 20:15:29 +0000776 break;
777 case BGP_OPEN_OPT_CAP:
Paul Jakma6d582722007-08-06 15:21:45 +0000778 ret = bgp_capability_parse (peer, opt_length, &error);
paul718e3742002-12-13 20:15:29 +0000779 *capability = 1;
780 break;
781 default:
782 bgp_notify_send (peer,
783 BGP_NOTIFY_OPEN_ERR,
784 BGP_NOTIFY_OPEN_UNSUP_PARAM);
785 ret = -1;
786 break;
787 }
788
789 /* Parse error. To accumulate all unsupported capability codes,
790 bgp_capability_parse does not return -1 when encounter
791 unsupported capability code. To detect that, please check
792 error and erro_data pointer, like below. */
793 if (ret < 0)
794 return -1;
paul718e3742002-12-13 20:15:29 +0000795 }
796
797 /* All OPEN option is parsed. Check capability when strict compare
798 flag is enabled.*/
799 if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
800 {
801 /* If Unsupported Capability exists. */
802 if (error != error_data)
803 {
804 bgp_notify_send_with_data (peer,
805 BGP_NOTIFY_OPEN_ERR,
806 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
807 error_data, error - error_data);
808 return -1;
809 }
810
811 /* Check local capability does not negotiated with remote
812 peer. */
813 if (! strict_capability_same (peer))
814 {
815 bgp_notify_send (peer,
816 BGP_NOTIFY_OPEN_ERR,
817 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
818 return -1;
819 }
820 }
821
822 /* Check there is no common capability send Unsupported Capability
823 error. */
824 if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
825 {
826 if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
827 && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
828 && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
829 && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
830 && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
831 {
832 plog_err (peer->log, "%s [Error] No common capability", peer->host);
833
834 if (error != error_data)
835
836 bgp_notify_send_with_data (peer,
837 BGP_NOTIFY_OPEN_ERR,
838 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
839 error_data, error - error_data);
840 else
841 bgp_notify_send (peer,
842 BGP_NOTIFY_OPEN_ERR,
843 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
844 return -1;
845 }
846 }
847 return 0;
848}
849
paul94f2b392005-06-28 12:44:16 +0000850static void
paul718e3742002-12-13 20:15:29 +0000851bgp_open_capability_orf (struct stream *s, struct peer *peer,
852 afi_t afi, safi_t safi, u_char code)
853{
854 u_char cap_len;
855 u_char orf_len;
856 unsigned long capp;
857 unsigned long orfp;
858 unsigned long numberp;
859 int number_of_orfs = 0;
860
861 if (safi == SAFI_MPLS_VPN)
862 safi = BGP_SAFI_VPNV4;
863
864 stream_putc (s, BGP_OPEN_OPT_CAP);
paul9985f832005-02-09 15:51:56 +0000865 capp = stream_get_endp (s); /* Set Capability Len Pointer */
paul718e3742002-12-13 20:15:29 +0000866 stream_putc (s, 0); /* Capability Length */
867 stream_putc (s, code); /* Capability Code */
paul9985f832005-02-09 15:51:56 +0000868 orfp = stream_get_endp (s); /* Set ORF Len Pointer */
paul718e3742002-12-13 20:15:29 +0000869 stream_putc (s, 0); /* ORF Length */
870 stream_putw (s, afi);
871 stream_putc (s, 0);
872 stream_putc (s, safi);
paul9985f832005-02-09 15:51:56 +0000873 numberp = stream_get_endp (s); /* Set Number Pointer */
paul718e3742002-12-13 20:15:29 +0000874 stream_putc (s, 0); /* Number of ORFs */
875
876 /* Address Prefix ORF */
877 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
878 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
879 {
880 stream_putc (s, (code == CAPABILITY_CODE_ORF ?
881 ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
882
883 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
884 && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
885 {
886 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
887 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
888 stream_putc (s, ORF_MODE_BOTH);
889 }
890 else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
891 {
892 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
893 stream_putc (s, ORF_MODE_SEND);
894 }
895 else
896 {
897 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
898 stream_putc (s, ORF_MODE_RECEIVE);
899 }
900 number_of_orfs++;
901 }
902
903 /* Total Number of ORFs. */
904 stream_putc_at (s, numberp, number_of_orfs);
905
906 /* Total ORF Len. */
paul9985f832005-02-09 15:51:56 +0000907 orf_len = stream_get_endp (s) - orfp - 1;
paul718e3742002-12-13 20:15:29 +0000908 stream_putc_at (s, orfp, orf_len);
909
910 /* Total Capability Len. */
paul9985f832005-02-09 15:51:56 +0000911 cap_len = stream_get_endp (s) - capp - 1;
paul718e3742002-12-13 20:15:29 +0000912 stream_putc_at (s, capp, cap_len);
913}
914
915/* Fill in capability open option to the packet. */
916void
917bgp_open_capability (struct stream *s, struct peer *peer)
918{
919 u_char len;
920 unsigned long cp;
921 afi_t afi;
922 safi_t safi;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000923 as_t local_as;
paul718e3742002-12-13 20:15:29 +0000924
925 /* Remember current pointer for Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +0000926 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +0000927
928 /* Opt Parm Len. */
929 stream_putc (s, 0);
930
931 /* Do not send capability. */
932 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
933 || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
934 return;
935
paul718e3742002-12-13 20:15:29 +0000936 /* IPv4 unicast. */
937 if (peer->afc[AFI_IP][SAFI_UNICAST])
938 {
939 peer->afc_adv[AFI_IP][SAFI_UNICAST] = 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_UNICAST);
947 }
948 /* IPv4 multicast. */
949 if (peer->afc[AFI_IP][SAFI_MULTICAST])
950 {
951 peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 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);
958 stream_putc (s, SAFI_MULTICAST);
959 }
960 /* IPv4 VPN */
961 if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
962 {
963 peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
964 stream_putc (s, BGP_OPEN_OPT_CAP);
965 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
966 stream_putc (s, CAPABILITY_CODE_MP);
967 stream_putc (s, CAPABILITY_CODE_MP_LEN);
968 stream_putw (s, AFI_IP);
969 stream_putc (s, 0);
970 stream_putc (s, BGP_SAFI_VPNV4);
971 }
972#ifdef HAVE_IPV6
973 /* IPv6 unicast. */
974 if (peer->afc[AFI_IP6][SAFI_UNICAST])
975 {
976 peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 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_UNICAST);
984 }
985 /* IPv6 multicast. */
986 if (peer->afc[AFI_IP6][SAFI_MULTICAST])
987 {
988 peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
989 stream_putc (s, BGP_OPEN_OPT_CAP);
990 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
991 stream_putc (s, CAPABILITY_CODE_MP);
992 stream_putc (s, CAPABILITY_CODE_MP_LEN);
993 stream_putw (s, AFI_IP6);
994 stream_putc (s, 0);
995 stream_putc (s, SAFI_MULTICAST);
996 }
997#endif /* HAVE_IPV6 */
998
999 /* Route refresh. */
hassoc9502432005-02-01 22:01:48 +00001000 SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
1001 stream_putc (s, BGP_OPEN_OPT_CAP);
1002 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
1003 stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
1004 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
1005 stream_putc (s, BGP_OPEN_OPT_CAP);
1006 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
1007 stream_putc (s, CAPABILITY_CODE_REFRESH);
1008 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
paul718e3742002-12-13 20:15:29 +00001009
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001010 /* AS4 */
1011 SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
1012 stream_putc (s, BGP_OPEN_OPT_CAP);
1013 stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
1014 stream_putc (s, CAPABILITY_CODE_AS4);
1015 stream_putc (s, CAPABILITY_CODE_AS4_LEN);
1016 if ( peer->change_local_as )
1017 local_as = peer->change_local_as;
1018 else
1019 local_as = peer->local_as;
1020 stream_putl (s, local_as );
1021
paul718e3742002-12-13 20:15:29 +00001022 /* ORF capability. */
1023 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
1024 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
1025 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
1026 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
1027 {
1028 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
1029 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
1030 }
1031
1032 /* Dynamic capability. */
1033 if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
1034 {
1035 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
1036 stream_putc (s, BGP_OPEN_OPT_CAP);
1037 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
1038 stream_putc (s, CAPABILITY_CODE_DYNAMIC);
1039 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
1040 }
1041
hasso538621f2004-05-21 09:31:30 +00001042 /* Graceful restart capability */
1043 if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
1044 {
1045 SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV);
1046 stream_putc (s, BGP_OPEN_OPT_CAP);
1047 stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2);
1048 stream_putc (s, CAPABILITY_CODE_RESTART);
1049 stream_putc (s, CAPABILITY_CODE_RESTART_LEN);
1050 stream_putw (s, peer->bgp->restart_time);
1051 }
1052
paul718e3742002-12-13 20:15:29 +00001053 /* Total Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +00001054 len = stream_get_endp (s) - cp - 1;
paul718e3742002-12-13 20:15:29 +00001055 stream_putc_at (s, cp, len);
1056}