summaryrefslogtreecommitdiff
path: root/bgpd/bgp_open.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_open.c')
-rw-r--r--bgpd/bgp_open.c772
1 files changed, 427 insertions, 345 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index e44bd2a0..d4f7cdf5 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "thread.h"
#include "log.h"
#include "command.h"
+#include "memory.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -50,25 +51,28 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
{
char *pnt;
char *end;
- struct capability cap;
+ struct capability_mp_data mpc;
+ struct capability_header *hdr;
pnt = peer->notify.data;
end = pnt + peer->notify.length;
-
+
while (pnt < end)
{
- memcpy(&cap, pnt, sizeof(struct capability));
-
- if (pnt + 2 > end)
+ if (pnt + sizeof (struct capability_mp_data) + 2 > end)
return;
- if (pnt + (cap.length + 2) > end)
+
+ hdr = (struct capability_header *)pnt;
+ if (pnt + hdr->length + 2 > end)
return;
- if (cap.code == CAPABILITY_CODE_MP)
+ memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data));
+
+ if (hdr->code == CAPABILITY_CODE_MP)
{
vty_out (vty, " Capability error for: Multi protocol ");
- switch (ntohs (cap.mpc.afi))
+ switch (ntohs (mpc.afi))
{
case AFI_IP:
vty_out (vty, "AFI IPv4, ");
@@ -77,10 +81,10 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
vty_out (vty, "AFI IPv6, ");
break;
default:
- vty_out (vty, "AFI Unknown %d, ", ntohs (cap.mpc.afi));
+ vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
break;
}
- switch (cap.mpc.safi)
+ switch (mpc.safi)
{
case SAFI_UNICAST:
vty_out (vty, "SAFI Unicast");
@@ -95,88 +99,87 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
vty_out (vty, "SAFI MPLS-VPN");
break;
default:
- vty_out (vty, "SAFI Unknown %d ", cap.mpc.safi);
+ vty_out (vty, "SAFI Unknown %d ", mpc.safi);
break;
}
vty_out (vty, "%s", VTY_NEWLINE);
}
- else if (cap.code >= 128)
+ else if (hdr->code >= 128)
vty_out (vty, " Capability error: vendor specific capability code %d",
- cap.code);
+ hdr->code);
else
vty_out (vty, " Capability error: unknown capability code %d",
- cap.code);
+ hdr->code);
- pnt += cap.length + 2;
+ pnt += hdr->length + 2;
}
}
-/* Set negotiated capability value. */
-static int
-bgp_capability_mp (struct peer *peer, struct capability *cap)
+static void
+bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
{
- if (ntohs (cap->mpc.afi) == AFI_IP)
- {
- if (cap->mpc.safi == SAFI_UNICAST)
- {
- peer->afc_recv[AFI_IP][SAFI_UNICAST] = 1;
-
- if (peer->afc[AFI_IP][SAFI_UNICAST])
- peer->afc_nego[AFI_IP][SAFI_UNICAST] = 1;
- else
- return -1;
- }
- else if (cap->mpc.safi == SAFI_MULTICAST)
- {
- peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 1;
-
- if (peer->afc[AFI_IP][SAFI_MULTICAST])
- peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 1;
- else
- return -1;
- }
- else if (cap->mpc.safi == BGP_SAFI_VPNV4)
- {
- peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 1;
+ mpc->afi = stream_getw (s);
+ mpc->reserved = stream_getc (s);
+ mpc->safi = stream_getc (s);
+}
- if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
- peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 1;
- else
- return -1;
- }
- else
- return -1;
- }
-#ifdef HAVE_IPV6
- else if (ntohs (cap->mpc.afi) == AFI_IP6)
+int
+bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
+{
+ /* VPNvX are AFI specific */
+ if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4)
+ || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6))
{
- if (cap->mpc.safi == SAFI_UNICAST)
- {
- peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 1;
-
- if (peer->afc[AFI_IP6][SAFI_UNICAST])
- peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 1;
- else
- return -1;
- }
- else if (cap->mpc.safi == SAFI_MULTICAST)
- {
- peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 1;
-
- if (peer->afc[AFI_IP6][SAFI_MULTICAST])
- peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 1;
- else
- return -1;
- }
- else
- return -1;
+ zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi);
+ return 0;
}
-#endif /* HAVE_IPV6 */
- else
+
+ switch (afi)
{
- /* Unknown Address Family. */
- return -1;
+ case AFI_IP:
+#ifdef HAVE_IPV6
+ case AFI_IP6:
+#endif
+ switch (*safi)
+ {
+ /* BGP VPNvX SAFI isn't contigious with others, remap */
+ case BGP_SAFI_VPNV4:
+ case BGP_SAFI_VPNV6:
+ *safi = SAFI_MPLS_VPN;
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
+ case SAFI_MPLS_VPN:
+ return 1;
+ }
}
+ zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
+
+ return 0;
+}
+
+/* Set negotiated capability value. */
+static int
+bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
+{
+ struct capability_mp_data mpc;
+ struct stream *s = BGP_INPUT (peer);
+
+ bgp_capability_mp_data (s, &mpc);
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
+ peer->host, mpc.afi, mpc.safi);
+
+ if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
+ return -1;
+
+ /* Now safi remapped, and afi/safi are valid array indices */
+ peer->afc_recv[mpc.afi][mpc.safi] = 1;
+
+ if (peer->afc[mpc.afi][mpc.safi])
+ peer->afc_nego[mpc.safi][mpc.safi] = 1;
+ else
+ return -1;
return 0;
}
@@ -190,98 +193,133 @@ bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
peer->host, afi, safi, type, mode);
}
+static struct message orf_type_str[] =
+{
+ { ORF_TYPE_PREFIX, "Prefixlist" },
+ { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" },
+};
+static int orf_type_str_max = sizeof(orf_type_str)/sizeof(orf_type_str[0]);
+
+static struct message orf_mode_str[] =
+{
+ { ORF_MODE_RECEIVE, "Receive" },
+ { ORF_MODE_SEND, "Send" },
+ { ORF_MODE_BOTH, "Both" },
+};
+static int orf_mode_str_max = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]);
+
static int
-bgp_capability_orf (struct peer *peer, struct capability *cap,
- u_char *pnt)
+bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
{
- afi_t afi = ntohs(cap->mpc.afi);
- safi_t safi = cap->mpc.safi;
- u_char number_of_orfs;
+ struct stream *s = BGP_INPUT (peer);
+ struct capability_orf_entry entry;
+ afi_t afi;
+ safi_t safi;
u_char type;
u_char mode;
u_int16_t sm_cap = 0; /* capability send-mode receive */
u_int16_t rm_cap = 0; /* capability receive-mode receive */
int i;
- /* Check length. */
- if (cap->length < 7)
- {
- zlog_info ("%s ORF Capability length error %d",
- peer->host, cap->length);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
-
+ /* ORF Entry header */
+ bgp_capability_mp_data (s, &entry.mpc);
+ entry.num = stream_getc (s);
+ afi = entry.mpc.afi;
+ safi = entry.mpc.safi;
+
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has ORF CAP(%s) for afi/safi: %u/%u",
- peer->host, (cap->code == CAPABILITY_CODE_ORF ?
- "new" : "old"), afi, safi);
+ zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
+ peer->host, entry.mpc.afi, entry.mpc.safi);
/* Check AFI and SAFI. */
- if ((afi != AFI_IP && afi != AFI_IP6)
- || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
- && safi != BGP_SAFI_VPNV4))
+ if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
+ {
+ zlog_info ("%s Addr-family %d/%d not supported."
+ " Ignoring the ORF capability",
+ peer->host, entry.mpc.afi, entry.mpc.safi);
+ return 0;
+ }
+
+ /* validate number field */
+ if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
{
- zlog_info ("%s Addr-family %d/%d not supported. Ignoring the ORF capability",
- peer->host, afi, safi);
+ zlog_info ("%s ORF Capability entry length error,"
+ " Cap length %u, num %u",
+ peer->host, hdr->length, entry.num);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
- number_of_orfs = *pnt++;
-
- for (i = 0 ; i < number_of_orfs ; i++)
+ for (i = 0 ; i < entry.num ; i++)
{
- type = *pnt++;
- mode = *pnt++;
-
+ type = stream_getc(s);
+ mode = stream_getc(s);
+
/* ORF Mode error check */
- if (mode != ORF_MODE_BOTH && mode != ORF_MODE_SEND
- && mode != ORF_MODE_RECEIVE)
- {
- bgp_capability_orf_not_support (peer, afi, safi, type, mode);
- continue;
+ switch (mode)
+ {
+ case ORF_MODE_BOTH:
+ case ORF_MODE_SEND:
+ case ORF_MODE_RECEIVE:
+ break;
+ default:
+ bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+ continue;
}
+ /* ORF Type and afi/safi error checks */
+ /* capcode versus type */
+ switch (hdr->code)
+ {
+ case CAPABILITY_CODE_ORF:
+ switch (type)
+ {
+ case ORF_TYPE_PREFIX:
+ break;
+ default:
+ bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+ continue;
+ }
+ break;
+ case CAPABILITY_CODE_ORF_OLD:
+ switch (type)
+ {
+ case ORF_TYPE_PREFIX_OLD:
+ break;
+ default:
+ bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+ continue;
+ }
+ break;
+ default:
+ bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+ continue;
+ }
+
+ /* AFI vs SAFI */
+ if (!((afi == AFI_IP && safi == SAFI_UNICAST)
+ || (afi == AFI_IP && safi == SAFI_MULTICAST)
+ || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
+ {
+ bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+ continue;
+ }
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s OPEN has %s ORF capability"
+ " as %s for afi/safi: %d/%d",
+ peer->host, LOOKUP (orf_type_str, type),
+ LOOKUP (orf_mode_str, mode),
+ entry.mpc.afi, safi);
- /* ORF Type and afi/safi error check */
- if (cap->code == CAPABILITY_CODE_ORF)
+ if (hdr->code == CAPABILITY_CODE_ORF)
{
- if (type == ORF_TYPE_PREFIX &&
- ((afi == AFI_IP && safi == SAFI_UNICAST)
- || (afi == AFI_IP && safi == SAFI_MULTICAST)
- || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
- {
- sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
- rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d",
- peer->host, ORF_TYPE_PREFIX, (mode == ORF_MODE_SEND ? "SEND" :
- mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi);
- }
- else
- {
- bgp_capability_orf_not_support (peer, afi, safi, type, mode);
- continue;
- }
+ sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
+ rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
}
- else if (cap->code == CAPABILITY_CODE_ORF_OLD)
+ else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
{
- if (type == ORF_TYPE_PREFIX_OLD &&
- ((afi == AFI_IP && safi == SAFI_UNICAST)
- || (afi == AFI_IP && safi == SAFI_MULTICAST)
- || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
- {
- sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
- rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d",
- peer->host, ORF_TYPE_PREFIX_OLD, (mode == ORF_MODE_SEND ? "SEND" :
- mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi);
- }
- else
- {
- bgp_capability_orf_not_support (peer, afi, safi, type, mode);
- continue;
- }
+ sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
+ rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
}
else
{
@@ -306,206 +344,258 @@ bgp_capability_orf (struct peer *peer, struct capability *cap,
return 0;
}
-/* Parse given capability. */
static int
-bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length,
- u_char **error)
+bgp_capability_orf (struct peer *peer, struct capability_header *hdr)
{
- int ret;
- u_char *end;
- struct capability cap;
-
- end = pnt + length;
-
- while (pnt < end)
+ struct stream *s = BGP_INPUT (peer);
+ size_t end = stream_get_getp (s) + hdr->length;
+
+ assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
+
+ /* We must have at least one ORF entry, as the caller has already done
+ * minimum length validation for the capability code - for ORF there must
+ * at least one ORF entry (header and unknown number of pairs of bytes).
+ */
+ do
{
- afi_t afi;
- safi_t safi;
+ if (bgp_capability_orf_entry (peer, hdr) == -1)
+ return -1;
+ }
+ while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
+
+ return 0;
+}
- /* Fetch structure to the byte stream. */
- memcpy (&cap, pnt, sizeof (struct capability));
+static int
+bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
+{
+ struct stream *s = BGP_INPUT (peer);
+ u_int16_t restart_flag_time;
+ int restart_bit = 0;
+ size_t end = stream_get_getp (s) + caphdr->length;
+
+ SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
+ restart_flag_time = stream_getw(s);
+ if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
+ restart_bit = 1;
+ UNSET_FLAG (restart_flag_time, 0xF000);
+ peer->v_gr_restart = restart_flag_time;
- afi = ntohs(cap.mpc.afi);
- safi = cap.mpc.safi;
+ if (BGP_DEBUG (normal, NORMAL))
+ {
+ zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
+ zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
+ peer->host, restart_bit ? " " : " not ",
+ peer->v_gr_restart);
+ }
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has CAPABILITY code: %d, length %d",
- peer->host, cap.code, cap.length);
+ while (stream_get_getp (s) + 4 < end)
+ {
+ afi_t afi = stream_getw (s);
+ safi_t safi = stream_getc (s);
+ u_char flag = stream_getc (s);
+
+ if (!bgp_afi_safi_valid_indices (afi, &safi))
+ {
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
+ " Ignore the Graceful Restart capability",
+ peer->host, afi, safi);
+ }
+ else if (!peer->afc[afi][safi])
+ {
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
+ " Ignore the Graceful Restart capability",
+ peer->host, afi, safi);
+ }
+ else
+ {
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Address family %s is%spreserved", peer->host,
+ afi_safi_print (afi, safi),
+ CHECK_FLAG (peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV)
+ ? " " : " not ");
+
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
+ if (CHECK_FLAG (flag, RESTART_F_BIT))
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
+
+ }
+ }
+ return 0;
+}
+static struct message capcode_str[] =
+{
+ { 0, ""},
+ { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
+ { CAPABILITY_CODE_REFRESH, "Route Refresh" },
+ { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" },
+ { CAPABILITY_CODE_RESTART, "Graceful Restart" },
+ { CAPABILITY_CODE_AS4, "4-octet AS number" },
+ { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
+ { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
+ { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
+};
+int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]);
+
+/* Minimum sizes for length field of each cap (so not inc. the header) */
+static size_t cap_minsizes[] =
+{
+ [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data),
+ [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
+ [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry),
+ [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr) - 2,
+ [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
+ [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
+ [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
+ [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
+};
+
+/* Parse given capability.
+ * XXX: This is reading into a stream, but not using stream API
+ */
+static int
+bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
+{
+ int ret;
+ struct stream *s = BGP_INPUT (peer);
+ size_t end = stream_get_getp (s) + length;
+
+ assert (STREAM_READABLE (s) >= length);
+
+ while (stream_get_getp (s) < end)
+ {
+ size_t start;
+ u_char *sp = stream_pnt (s);
+ struct capability_header caphdr;
+
/* We need at least capability code and capability length. */
- if (pnt + 2 > end)
+ if (stream_get_getp(s) + 2 > end)
{
- zlog_info ("%s Capability length error", peer->host);
+ zlog_info ("%s Capability length error (< header)", peer->host);
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
-
- /* Capability length check. */
- if (pnt + (cap.length + 2) > end)
+
+ caphdr.code = stream_getc (s);
+ caphdr.length = stream_getc (s);
+ start = stream_get_getp (s);
+
+ /* Capability length check sanity check. */
+ if (start + caphdr.length > end)
{
- zlog_info ("%s Capability length error", peer->host);
+ zlog_info ("%s Capability length error (< length)", peer->host);
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
-
- /* We know MP Capability Code. */
- if (cap.code == CAPABILITY_CODE_MP)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
- peer->host, afi, safi);
-
- /* Ignore capability when override-capability is set. */
- if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- {
- /* Set negotiated value. */
- ret = bgp_capability_mp (peer, &cap);
-
- /* Unsupported Capability. */
- if (ret < 0)
- {
- /* Store return data. */
- memcpy (*error, &cap, cap.length + 2);
- *error += cap.length + 2;
- }
- }
- }
- else if (cap.code == CAPABILITY_CODE_REFRESH
- || cap.code == CAPABILITY_CODE_REFRESH_OLD)
- {
- /* Check length. */
- if (cap.length != CAPABILITY_CODE_REFRESH_LEN)
- {
- zlog_info ("%s Route Refresh Capability length error %d",
- peer->host, cap.length);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has ROUTE-REFRESH capability(%s) for all address-families",
- peer->host,
- cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new");
-
- /* BGP refresh capability */
- if (cap.code == CAPABILITY_CODE_REFRESH_OLD)
- SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
- else
- SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
- }
- else if (cap.code == CAPABILITY_CODE_ORF
- || cap.code == CAPABILITY_CODE_ORF_OLD)
- bgp_capability_orf (peer, &cap, pnt + sizeof (struct capability));
- else if (cap.code == CAPABILITY_CODE_RESTART)
- {
- struct graceful_restart_af graf;
- u_int16_t restart_flag_time;
- int restart_bit = 0;
- u_char *restart_pnt;
- u_char *restart_end;
-
- /* Check length. */
- if (cap.length < CAPABILITY_CODE_RESTART_LEN)
- {
- zlog_info ("%s Graceful Restart Capability length error %d",
- peer->host, cap.length);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
-
- SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
- restart_flag_time = ntohs(cap.mpc.afi);
- if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
- restart_bit = 1;
- UNSET_FLAG (restart_flag_time, 0xF000);
- peer->v_gr_restart = restart_flag_time;
-
- if (BGP_DEBUG (normal, NORMAL))
- {
- zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
- zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
- peer->host, restart_bit ? " " : " not ",
- peer->v_gr_restart);
- }
-
- restart_pnt = pnt + 4;
- restart_end = pnt + cap.length + 2;
-
- while (restart_pnt < restart_end)
- {
- memcpy (&graf, restart_pnt, sizeof (struct graceful_restart_af));
-
- afi = ntohs(graf.afi);
- safi = graf.safi;
-
- if (CHECK_FLAG (graf.flag, RESTART_F_BIT))
- SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
-
- if (strcmp (afi_safi_print (afi, safi), "Unknown") == 0)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported. I gnore the Graceful Restart capability",
- peer->host, afi, safi);
- }
- else if (! peer->afc[afi][safi])
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled. Ignore the Graceful Restart capability",
- peer->host, afi, safi);
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Address family %s is%spreserved", peer->host,
- afi_safi_print (afi, safi),
- CHECK_FLAG (peer->af_cap[afi][safi],
- PEER_CAP_RESTART_AF_PRESERVE_RCV)
- ? " " : " not ");
-
- SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
- }
- restart_pnt += 4;
- }
- }
- else if (cap.code == CAPABILITY_CODE_DYNAMIC)
- {
- /* Check length. */
- if (cap.length != CAPABILITY_CODE_DYNAMIC_LEN)
- {
- zlog_info ("%s Dynamic Capability length error %d",
- peer->host, cap.length);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s OPEN has DYNAMIC capability", peer->host);
-
- SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
- }
-
- else if (cap.code > 128)
- {
- /* We don't send Notification for unknown vendor specific
- capabilities. It seems reasonable for now... */
- zlog_warn ("%s Vendor specific capability %d",
- peer->host, cap.code);
- }
- else
- {
- zlog_warn ("%s unrecognized capability code: %d - ignored",
- peer->host, cap.code);
- memcpy (*error, &cap, cap.length + 2);
- *error += cap.length + 2;
- }
-
- pnt += cap.length + 2;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s OPEN has %s capability (%u), length %u",
+ peer->host,
+ LOOKUP (capcode_str, caphdr.code),
+ caphdr.code, caphdr.length);
+
+ /* Length sanity check, type-specific, for known capabilities */
+ switch (caphdr.code)
+ {
+ case CAPABILITY_CODE_MP:
+ case CAPABILITY_CODE_REFRESH:
+ case CAPABILITY_CODE_REFRESH_OLD:
+ case CAPABILITY_CODE_ORF:
+ case CAPABILITY_CODE_ORF_OLD:
+ case CAPABILITY_CODE_RESTART:
+ case CAPABILITY_CODE_DYNAMIC:
+ /* Check length. */
+ if (caphdr.length < cap_minsizes[caphdr.code])
+ {
+ zlog_info ("%s %s Capability length error: got %u,"
+ " expected at least %u",
+ peer->host,
+ LOOKUP (capcode_str, caphdr.code),
+ caphdr.length, cap_minsizes[caphdr.code]);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ return -1;
+ }
+ /* we deliberately ignore unknown codes, see below */
+ default:
+ break;
+ }
+
+ switch (caphdr.code)
+ {
+ case CAPABILITY_CODE_MP:
+ {
+ /* Ignore capability when override-capability is set. */
+ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ {
+ /* Set negotiated value. */
+ ret = bgp_capability_mp (peer, &caphdr);
+
+ /* Unsupported Capability. */
+ if (ret < 0)
+ {
+ /* Store return data. */
+ memcpy (*error, sp, caphdr.length + 2);
+ *error += caphdr.length + 2;
+ }
+ }
+ }
+ break;
+ case CAPABILITY_CODE_REFRESH:
+ case CAPABILITY_CODE_REFRESH_OLD:
+ {
+ /* BGP refresh capability */
+ if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
+ SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+ else
+ SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+ }
+ break;
+ case CAPABILITY_CODE_ORF:
+ case CAPABILITY_CODE_ORF_OLD:
+ if (bgp_capability_orf (peer, &caphdr))
+ return -1;
+ break;
+ case CAPABILITY_CODE_RESTART:
+ if (bgp_capability_restart (peer, &caphdr))
+ return -1;
+ break;
+ case CAPABILITY_CODE_DYNAMIC:
+ SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
+ break;
+ default:
+ if (caphdr.code > 128)
+ {
+ /* We don't send Notification for unknown vendor specific
+ capabilities. It seems reasonable for now... */
+ zlog_warn ("%s Vendor specific capability %d",
+ peer->host, caphdr.code);
+ }
+ else
+ {
+ zlog_warn ("%s unrecognized capability code: %d - ignored",
+ peer->host, caphdr.code);
+ memcpy (*error, sp, caphdr.length + 2);
+ *error += caphdr.length + 2;
+ }
+ }
+ if (stream_get_getp(s) != (start + caphdr.length))
+ {
+ if (stream_get_getp(s) > (start + caphdr.length))
+ zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
+ peer->host, LOOKUP (capcode_str, caphdr.code),
+ caphdr.length);
+ stream_set_getp (s, start + caphdr.length);
+ }
}
return 0;
}
static int
-bgp_auth_parse (struct peer *peer, u_char *pnt, size_t length)
+bgp_auth_parse (struct peer *peer, size_t length)
{
bgp_notify_send (peer,
BGP_NOTIFY_OPEN_ERR,
@@ -530,30 +620,25 @@ int
bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
{
int ret;
- u_char *end;
- u_char opt_type;
- u_char opt_length;
- u_char *pnt;
u_char *error;
u_char error_data[BGP_MAX_PACKET_SIZE];
-
- /* Fetch pointer. */
- pnt = stream_pnt (peer->ibuf);
+ struct stream *s = BGP_INPUT(peer);
+ size_t end = stream_get_getp (s) + length;
ret = 0;
- opt_type = 0;
- opt_length = 0;
- end = pnt + length;
error = error_data;
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
peer->host, length);
- while (pnt < end)
+ while (stream_get_getp(s) < end)
{
- /* Check the length. */
- if (pnt + 2 > end)
+ u_char opt_type;
+ u_char opt_length;
+
+ /* Must have at least an OPEN option header */
+ if (STREAM_READABLE(s) < 2)
{
zlog_info ("%s Option length error", peer->host);
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
@@ -561,11 +646,11 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
}
/* Fetch option type and length. */
- opt_type = *pnt++;
- opt_length = *pnt++;
+ opt_type = stream_getc (s);
+ opt_length = stream_getc (s);
/* Option length check. */
- if (pnt + opt_length > end)
+ if (STREAM_READABLE (s) < opt_length)
{
zlog_info ("%s Option length error", peer->host);
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
@@ -582,10 +667,10 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
switch (opt_type)
{
case BGP_OPEN_OPT_AUTH:
- ret = bgp_auth_parse (peer, pnt, opt_length);
+ ret = bgp_auth_parse (peer, opt_length);
break;
case BGP_OPEN_OPT_CAP:
- ret = bgp_capability_parse (peer, pnt, opt_length, &error);
+ ret = bgp_capability_parse (peer, opt_length, &error);
*capability = 1;
break;
default:
@@ -602,9 +687,6 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
error and erro_data pointer, like below. */
if (ret < 0)
return -1;
-
- /* Forward pointer. */
- pnt += opt_length;
}
/* All OPEN option is parsed. Check capability when strict compare