summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp.h120
-rw-r--r--bgpd/bgp_common.c50
-rw-r--r--bgpd/bgp_common.h126
-rw-r--r--bgpd/bgp_connection.c16
-rw-r--r--bgpd/bgp_connection.h6
-rw-r--r--bgpd/bgp_fsm.c3
-rw-r--r--bgpd/bgp_msg_read.c1707
-rw-r--r--bgpd/bgp_msg_read.h4
-rw-r--r--bgpd/bgp_msg_write.c10
-rw-r--r--bgpd/bgp_notification.c102
-rw-r--r--bgpd/bgp_notification.h12
-rw-r--r--bgpd/bgp_open.h11
-rw-r--r--bgpd/bgp_open_state.c73
-rw-r--r--bgpd/bgp_open_state.h24
-rw-r--r--bgpd/bgp_packet.c2
-rw-r--r--bgpd/bgp_session.h16
-rw-r--r--lib/distribute.c66
-rw-r--r--lib/if_rmap.c54
-rw-r--r--lib/qafi_safi.h21
-rw-r--r--lib/stream.c7
-rw-r--r--lib/stream.h1
21 files changed, 1532 insertions, 899 deletions
diff --git a/bgpd/bgp.h b/bgpd/bgp.h
index 3b4f603c..3bcabd8e 100644
--- a/bgpd/bgp.h
+++ b/bgpd/bgp.h
@@ -164,8 +164,9 @@ typedef U16 BGP_MH_LEN_T ; /* length of message inc. header: octets */
typedef U8 BGP_MH_TYPE_T ; /* BGP message type */
typedef UBX BGP_MH_BODY_T ; /* rest is body of message */
+VALUE(BGP_MH_MARKER_L = sizeof(BGP_MH_MARKER_T)) ;
VALUE(BGP_MH_HEAD_L = /* message header length */
- sizeof(BGP_MH_MARKER_T)
+ BGP_MH_MARKER_L
+ sizeof(BGP_MH_LEN_T)
+ sizeof(BGP_MH_TYPE_T) ) ;
CONFIRM(BGP_MH_HEAD_L == 19) ; /* well known value ! */
@@ -192,7 +193,9 @@ enum BGP_MT
BGP_MT_KEEPALIVE = 4,
BGP_MT_ROUTE_REFRESH = 5, /* RFC2918 */
- BGP_MT_MAX = 5, /* max known message type */
+ BGP_MT_CAPABILITY = 6, /* draft-ietf-idr-dynamic-cap-10 */
+
+ BGP_MT_MAX = 6, /* max known message type */
BGP_MT_ROUTE_REFRESH_pre = 128 /* pre RFC2918 (Sep-2000) */
} ;
@@ -264,6 +267,9 @@ typedef UBX BGP_CAP_VALUE_T ; /* variable -- depending on code */
VALUE(BGP_CAP_MIN_L = sizeof(BGP_CAP_CODE_T) + sizeof(BGP_CAP_LEN_T)) ;
/* min len of a capability announcement */
+VALUE(BGP_CAP_MAX_L = 255) ; /* max len of a capability announcement */
+CONFIRM(sizeof(BGP_CAP_LEN_T) == 1) ;
+
enum /* order */
{
BGP_CAP_CODE,
@@ -284,7 +290,8 @@ enum BGP_CAN {
BGP_CAN_G_RESTART = 64, /* Graceful Restart RFC4724 */
BGP_CAN_AS4 = 65, /* Supports 4-octet AS number RFC4893 */
- /* 66, Deprecated 6-Apr-2003 */
+ BGP_CAN_DYNAMIC_CAP_old = 66, /* Dynamic Capability (draft 02) [Chen]
+ Deprecated 6-Apr-2003 */
BGP_CAN_DYNAMIC_CAP= 67, /* Dynamic Capability [Chen] */
BGP_CAN_MULTI_SESS = 68, /* Multisession Capability [Appanna] */
BGP_CAN_ADD_PATH = 69, /* ADD-PATH [draft-idr] */
@@ -437,6 +444,9 @@ enum BGP_NOMC
BGP_NOMC_FSM = 5, /* Finite State Machine Error */
BGP_NOMC_CEASE = 6, /* Cease RFC4486 */
+ BGP_NOMC_DYN_CAP = 7, /* Dynamic Capability
+ draft-ietf-idr-dynamic-cap-10.txt */
+
BGP_NOMC_MAX = 6 /* max known error code */
} ;
@@ -526,6 +536,17 @@ enum BGP_NOMS_CEASE /* BGP_NOMC_CEASE subcodes RFC4486 */
BGP_NOMS_C_MAX = 8 /* max known subcode */
} ;
+enum BGP_DYN_CAP /* BGP_NOMC_DYN_CAP subcodes
+ draft-ietf-idr-dynamic-cap-10.txt */
+{
+ BGP_NOMS_D_UNKN_SEQ = 1, /* Unknown Sequence Number MUST */
+ BGP_NOMS_D_INV_LEN = 2, /* Invalid Capability Length MUST */
+ BGP_NOMS_D_MALFORM = 3, /* Malformed Capability Length MUST */
+ BGP_NOMS_D_UNSUP = 4, /* Unsupported Capability MUST */
+
+ BGP_NOMS_D_MAX = 4 /* max known subcode */
+} ;
+
/* Keepalive Message (type = BGP_MT_KEEPALIVE) -------------------------------*/
VALUE(BGP_KAM_L = BGP_MH_HEAD_L) ; /* Keepalive message is entirely empty */
@@ -539,11 +560,11 @@ typedef U16 BGP_RRM_AFI_T ; /* Address Family Identifier */
typedef U8 BGP_RRM_RES_T ; /* reserved = 0 */
typedef U8 BGP_RRM_SAFI_T ; /* Subsequent Address Family Identifier */
-VALUE(BGP_RRM_L = BGP_MH_HEAD_L /* Route Refresh length */
- + sizeof(BGP_RRM_AFI_T)
- + sizeof(BGP_RRM_RES_T)
- + sizeof(BGP_RRM_SAFI_T) ) ;
-CONFIRM(BGP_RRM_L == 23) ; /* well known value ! */
+VALUE(BGP_RRM_MIN_L = BGP_MH_HEAD_L /* Route Refresh length */
+ + sizeof(BGP_RRM_AFI_T)
+ + sizeof(BGP_RRM_RES_T)
+ + sizeof(BGP_RRM_SAFI_T) ) ;
+CONFIRM(BGP_RRM_MIN_L == 23) ; /* well known value ! */
typedef U8 BGP_RRM_ORF_WHEN_T ; /* when to refresh -- see RFC5291 */
typedef UBX BGP_RRM_ORFS_T ; /* variable... see below */
@@ -625,6 +646,12 @@ VALUE(BGP_ORF_E_P_MIN_L = BGP_ORF_E_COM_L
+ sizeof(BGP_ORF_E_P_MAX_T)
+ sizeof(BGP_ORF_E_P_LEN_T) ) ;
+/* Dynamic Capability Message (type = BGP_MT_CAPABILITY) -----------------------
+ *
+ * If it's just header + 4 bytes, it's an RFC2918 Route Refresh request.
+ * If it's longer that that, it's an RFC5291 ORF
+ */
+
/*==============================================================================
* Capability Values
*/
@@ -645,47 +672,59 @@ VALUE(BGP_CAP_MPE_L = 4) ; /* Fixed length == 4 ! */
VALUE(BGP_CAP_RRF_L = 0) ; /* no value part */
-/* Outbound Route Filtering -- BGP_CAN_ORF -- RFC5291 ------------------------*/
-
-typedef U16 BGP_CAP_ORF_AFI_T ; /* Address Family Identifier */
-typedef U8 BGP_CAP_ORF_RES_T ; /* Reserved: 0 */
-typedef U8 BGP_CAP_ORF_SAFI_T ; /* Subsequent Address Family */
-typedef U8 BGP_CAP_ORF_COUNT_T ; /* number of ORF Types supported */
-typedef UBX BGP_CAP_ORF_CAN_T ; /* variable -- 2 byte entries as below */
-
-VALUE(BGP_CAP_ORF_MIN_L = sizeof(BGP_CAP_ORF_AFI_T)
- + sizeof(BGP_CAP_ORF_RES_T)
- + sizeof(BGP_CAP_ORF_SAFI_T)
- + sizeof(BGP_CAP_ORF_COUNT_T) ) ;
+/* Outbound Route Filtering -- BGP_CAN_ORF -- RFC5291 --------------------------
+ *
+ * The capability value is *one* or more of the following entries:
+ */
+typedef U16 BGP_CAP_ORFE_AFI_T ; /* Address Family Identifier */
+typedef U8 BGP_CAP_ORFE_RES_T ; /* Reserved: 0 */
+typedef U8 BGP_CAP_ORFE_SAFI_T ; /* Subsequent Address Family */
+typedef U8 BGP_CAP_ORFE_COUNT_T ; /* number of ORF Types supported */
+typedef UBX BGP_CAP_ORFE_TYPES_T ; /* variable -- 2 byte entries as below */
-VALUE(BGP_CAP_ORF_COUNT_O = sizeof(BGP_CAP_ORF_AFI_T)
- + sizeof(BGP_CAP_ORF_RES_T)
- + sizeof(BGP_CAP_ORF_SAFI_T) ) ;
+VALUE(BGP_CAP_ORFE_MIN_L = sizeof(BGP_CAP_ORFE_AFI_T)
+ + sizeof(BGP_CAP_ORFE_RES_T)
+ + sizeof(BGP_CAP_ORFE_SAFI_T)
+ + sizeof(BGP_CAP_ORFE_COUNT_T) ) ;
enum /* order */
{
- BGP_CAP_ORF_AFI,
- BGP_CAP_ORF_RES,
- BGP_CAP_ORF_SAFI,
- BGP_CAP_ORF_COUNT,
- BGP_CAP_ORF_CAN
+ BGP_CAP_ORFE_AFI,
+ BGP_CAP_ORFE_RES,
+ BGP_CAP_ORFE_SAFI,
+ BGP_CAP_ORFE_COUNT,
+ BGP_CAP_ORFE_TYPES
} ;
-/* Entries saying what ORF Types can be supported and how.....................*/
-
-typedef U8 BGP_CAP_ORFE_TYPE_T ; /* the ORF Type supported */
-typedef U8 BGP_CAP_ORFE_CAN_T ; /* what can do with ORF Type */
+/* Entries saying what ORF Types can be supported and how.......................
+ *
+ * There are BGP_CAP_ORF_COUNT of these.
+ */
+typedef U8 BGP_CAP_ORFT_TYPE_T ; /* the ORF Type supported */
+typedef U8 BGP_CAP_ORFT_MODE_T ; /* what can do with ORF Type */
-VALUE(BGP_CAP_ORFE_L = sizeof(BGP_CAP_ORFE_TYPE_T)
- + sizeof(BGP_CAP_ORFE_CAN_T)) ;
+VALUE(BGP_CAP_ORFT_L = sizeof(BGP_CAP_ORFT_TYPE_T)
+ + sizeof(BGP_CAP_ORFT_MODE_T)) ;
/* length of ORF capability Type entry */
+enum /* order */
+{
+ BGP_CAP_ORFT_TYPE,
+ BGP_CAP_ORFT_MODE,
+} ;
-/* Values for the BGP_CAP_ORFE_CAN field */
+/* Values for the BGP_CAP_ORFT_TYPE field */
+enum
+{
+ BGP_CAP_ORFT_T_PFIX = 64, /* Address Prefix ORF */
+ BGP_CAP_ORFT_T_PFIX_pre = 128, /* Address Prefix ORF, pre-RFC */
+} ;
+/* Values for the BGP_CAP_ORFT_MODE field */
enum
{
- BGP_CAP_ORFE_CAN_RECV = 1, /* willing to receive ) can be... */
- BGP_CAP_ORFE_CAN_SEND = 2 /* would like to send ) ... combined */
+ BGP_CAP_ORFT_M_RECV = 1, /* willing to receive */
+ BGP_CAP_ORFT_M_SEND = 2, /* would like to send */
+ BGP_CAP_ORFT_M_BOTH = 3 /* may be combined */
} ;
/* Multiple Routes to a Destination (Labels) -- BGP_CAN_M_ROUTES -- RFC3107 ----
@@ -734,6 +773,11 @@ typedef U32 BGP_CAP_AS4_MY_AS_T ; /* can do AS4, and this is me AS4-wise */
VALUE(BGP_CAP_AS4_L = sizeof(BGP_CAP_AS4_MY_AS_T)) ;
+/* Dynamic Capability -- BGP_CAN_DYNAMIC_CAP -- draft-10----------------------*/
+/* draft-ietf-idr-dynamic-cap-10 15-Jan-2010 */
+
+VALUE(BGP_CAP_DYN_L = 0) ;
+
/*==============================================================================
* Attributes -- form of the Path Attributes in an UPDATE Message
*
@@ -823,6 +867,8 @@ enum BGP_ASN {
BGP_ASN_RES2 = 65535, /* Start of Reservation 2 (0xFFFF) */
+ BGP_AS2_MAX = 65535, /* Last of the Mohicans (0xFFFF) */
+
BGP_AS4_DOC_S = AS4(1,0), /* Start of Docm. & Samples AS4 (65536) */
BGP_AS4_DOC_E = AS4(1,15), /* End (65531) */
diff --git a/bgpd/bgp_common.c b/bgpd/bgp_common.c
index 15ecdf3b..90281ff5 100644
--- a/bgpd/bgp_common.c
+++ b/bgpd/bgp_common.c
@@ -109,11 +109,12 @@ const iSAFI_t iSAFI_map[] =
} ;
/*==============================================================================
- * Convert iAFI/iSAFI => qafx_num_t
- * and qAFI/qSAFI => qafx_num_t
+ * Convert iAFI/iSAFI => qafx_num_t -- tolerates unknown/reserved
+ * and qAFI/qSAFI => qafx_num_t -- tolerates undef, but not unknown
*/
-/* iAFI/iSAFI = qafx_num_t unknowns => qafx_num_other
+/*------------------------------------------------------------------------------
+ * iAFI/iSAFI => qafx_num_t unknowns => qafx_num_other
* reserved => qafx_num_undef
*/
extern qafx_num_t
@@ -170,7 +171,8 @@ qafx_num_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi)
return qafx_num_other ;
} ;
-/* qAFI/qSAFI = qafx_num_t
+/*------------------------------------------------------------------------------
+ * qAFI/qSAFI => qafx_num_t
*
* NB: qAFI_undef with any qSAFI_xxx => qafx_num_undef
* qSAFI_undef with any qAFI_xxx => qafx_num_undef
@@ -228,3 +230,43 @@ qafx_num_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi)
zabort("invalid qAFI or qSAFI") ;
} ;
+
+/*==============================================================================
+ * Convert iAFI/iSAFI => qafx_bit_t -- tolerates unknown/reserved
+ * and qAFI/qSAFI => qafx_bit_t -- tolerates undef, but not unknown
+ */
+
+/*------------------------------------------------------------------------------
+ * iAFI/iSAFI => qafx_bit_t unknowns => 0
+ * reserved => 0
+ */
+extern qafx_bit_t
+qafx_bit_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi)
+{
+ qafx_num_t qn = qafx_num_from_iAFI_iSAFI(afi, safi) ;
+
+ if ((qn != qafx_num_undef) && (qn != qafx_num_other))
+ return qafx_bit(qn) ;
+ else
+ return 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * qAFI/qSAFI => qafx_bit_t
+ *
+ * NB: qAFI_undef with any qSAFI_xxx => 0
+ * qSAFI_undef with any qAFI_xxx => 0
+ * qSAFI_Unused qith any qAFI_xxx => 0
+ *
+ * NB: any unrecognised qAFI/qSAFI combinations => FATAL error
+ */
+extern qafx_bit_t
+qafx_bit_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi)
+{
+ qafx_num_t qn = qafx_num_from_qAFI_qSAFI(afi, safi) ;
+
+ if ((qn != qafx_num_undef) && (qn != qafx_num_other))
+ return qafx_bit(qn) ;
+ else
+ return 0 ;
+} ;
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index 221b255a..a2722ed1 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -25,7 +25,7 @@
#include <stdint.h>
#include "bgpd/bgp.h"
#include "qafi_safi.h"
-#include "confirm.h"
+#include "lib/zassert.h"
#ifndef Inline
#define Inline static inline
@@ -282,8 +282,11 @@ get_iSAFI(qafx_num_t num)
} ;
/*==============================================================================
- * Conversions for qAFI/qSAFI => qafx_num_t
- * and iAFI/iSAFI => qafx_num_t
+ * Conversions for iAFI/iSAFI => qafx_num_t
+ * and qAFI/qSAFI => qafx_num_t
+ *
+ * and iAFI/iSAFI => qafx_bit_t
+ * and qAFI/qSAFI => qafx_bit_t
*/
extern qafx_num_t
@@ -292,5 +295,122 @@ qafx_num_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) ;
extern qafx_num_t
qafx_num_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) ;
+extern qafx_bit_t
+qafx_bit_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) ;
+
+extern qafx_bit_t
+qafx_bit_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) ;
+
+/*==============================================================================
+ * Buffer sucking
+ *
+ *
+ */
+
+typedef uint8_t* ptr_t ;
+
+typedef struct sucker sucker_t ;
+typedef struct sucker* sucker ;
+struct sucker
+{
+ ptr_t start ; /* current known start */
+ ptr_t ptr ; /* current read pointer */
+ ptr_t end ; /* current known end */
+} ;
+
+Inline void
+suck_init(sucker sr, void* start, unsigned length)
+{
+ sr->start = (ptr_t)start ;
+ sr->ptr = (ptr_t)start ;
+ sr->end = (ptr_t)start + length ;
+}
+
+Inline int
+suck_left(sucker sr)
+{
+ return sr->end - sr->ptr ;
+} ;
+
+Inline int
+suck_total(sucker sr)
+{
+ return sr->end - sr->start ;
+} ;
+
+Inline ptr_t
+suck_start(sucker sr)
+{
+ return sr->start ;
+} ;
+
+Inline void
+suck_push(sucker sr, unsigned length, sucker sv)
+{
+ *sv = *sr ;
+ sr->start = sr->ptr ;
+ sr->end = sr->ptr + length ;
+ dassert(sr->end <= sv->end) ;
+} ;
+
+Inline void
+suck_pop(sucker sr, sucker sv)
+{
+ dassert((sr->ptr <= sr->end) && (sr->end <= sv->end)) ;
+ sr->start = sv->start ;
+ sr->ptr = sr->end ;
+ sr->end = sv->end ;
+} ;
+
+Inline void
+suck_pop_exact(sucker sr, sucker sv)
+{
+ dassert(sr->ptr == sr->end) ;
+ sr->start = sv->start ;
+ sr->end = sv->end ;
+} ;
+
+Inline void
+suck_x(sucker sr)
+{
+ ++sr->ptr ;
+ dassert(sr->ptr <= sr->end) ;
+} ;
+
+Inline void
+suck_nx(sucker sr, unsigned n)
+{
+ sr->ptr += n ;
+ dassert(sr->ptr <= sr->end) ;
+} ;
+
+Inline uint8_t
+suck_b(sucker sr)
+{
+ dassert(sr->ptr < sr->end) ;
+ return *sr->ptr++ ;
+} ;
+
+Inline uint16_t
+suck_w(sucker sr)
+{
+ uint16_t w ;
+ dassert((sr->ptr + 1) < sr->end) ;
+ w = *sr->ptr++ ;
+ return (w << 8) + *sr->ptr++ ;
+} ;
+
+Inline uint32_t
+suck_l(sucker sr)
+{
+ uint32_t l ;
+ dassert((sr->ptr + 3) < sr->end) ;
+ l = *sr->ptr++ ;
+ l = (l << 8) + *sr->ptr++ ;
+ l = (l << 8) + *sr->ptr++ ;
+ return (l << 8) + *sr->ptr++ ;
+} ;
+
+
#endif /* _QUAGGA_BGP_COMMON_H */
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index 8ceb9db6..2e10eaf1 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -126,8 +126,11 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
* * keepalive_timer_interval none -- set when connection is opened
* * as4 not AS4 conversation
* * route_refresh_pre not pre-RFC ROUTE-REFRESH
+ * * orf_prefix_pre not pre-RFC ORF by prefix
* * read_pending nothing pending
* * read_header not reading header
+ * * msg_type none -- set when reading message
+ * * msg_size none -- set when reading message
* * notification_pending nothing pending
* * wbuff all pointers NULL -- empty buffer
*/
@@ -232,8 +235,7 @@ bgp_connection_make_primary(bgp_connection connection)
* Copy the negotiated hold_timer_interval and keepalive_timer_interval
* Copy the su_local and su_remote
*/
- session->open_recv = connection->open_recv ;
- connection->open_recv = NULL ; /* no longer interested in this */
+ bgp_open_state_set_mov(&session->open_recv, &connection->open_recv) ;
XFREE(MTYPE_BGP_PEER_HOST, connection->host) ;
bgp_connection_init_host(connection, "") ;
@@ -243,6 +245,7 @@ bgp_connection_make_primary(bgp_connection connection)
session->as4 = connection->as4 ;
session->route_refresh_pre = connection->route_refresh_pre ;
+ session->orf_prefix_pre = connection->orf_prefix_pre ;
sockunion_set_mov(&session->su_local, &connection->su_local) ;
sockunion_set_mov(&session->su_remote, &connection->su_remote) ;
@@ -895,9 +898,9 @@ bgp_connection_read_action(qps_file qf, void* file_info)
*
* Exits loop iff completes a BGP message.
*/
- while (1)
+ while (want > 0)
{
- ret = stream_read_unblock(connection->ibuf, qps_file_fd(&connection->qf),
+ ret = stream_read_nonblock(connection->ibuf, qps_file_fd(&connection->qf),
want) ;
if (ret >= 0)
{
@@ -915,8 +918,6 @@ bgp_connection_read_action(qps_file qf, void* file_info)
want = bgp_msg_check_header(connection) ;
/* returns balance of message */
- if (want < 0)
- return ; /* failed in header check */
}
else
{
@@ -925,6 +926,9 @@ bgp_connection_read_action(qps_file qf, void* file_info)
} ;
} ;
+ if (want < 0)
+ return ; /* failed in header check */
+
/* Deal with the BGP message. MUST remove from ibuf before returns ! */
bgp_msg_dispatch(connection) ;
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index 2bffc5be..5ce623cd 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -151,13 +151,17 @@ struct bgp_connection
flag_t as4 ; /* subject to negotiation */
flag_t route_refresh_pre ; /* subject to negotiation */
+ flag_t orf_prefix_pre ; /* subject to negotiation */
struct qtimer hold_timer ;
struct qtimer keepalive_timer ;
struct stream* ibuf ; /* a single input "stream" */
unsigned read_pending ; /* how much input waiting for */
- int read_header ; /* reading message header */
+
+ flag_t read_header ; /* reading message header */
+ uint8_t msg_type ; /* copy of message type */
+ bgp_size_t msg_size ; /* size of message *body* */
struct stream* obuf ; /* a single output "stream" */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index d26e7e6e..cb899797 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1924,7 +1924,8 @@ static bgp_fsm_action(bgp_fsm_recv_open)
bgp_connection loser ;
/* NB: bgp_id in open_state is in *host* order */
- loser = (session->open_send->bgp_id < sibling->open_recv->bgp_id)
+ loser = (ntohl(session->open_send->bgp_id) <
+ ntohl(sibling->open_recv->bgp_id))
? connection
: sibling ;
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index bbe8796d..58a80485 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -35,26 +35,7 @@
/* prototypes */
-static int bgp_msg_marker_all_one (struct stream *s, int length);
static int bgp_msg_open_receive (bgp_connection connection, bgp_size_t size);
-static as_t bgp_msg_peek_for_as4_capability (bgp_connection connection,
- u_char length);
-static as_t bgp_msg_capability_as4 (bgp_connection connection,
- struct capability_header *hdr);
-static int bgp_msg_open_option_parse (bgp_connection connection, u_char length,
- int *capability);
-static int bgp_msg_capability_parse (bgp_connection connection, size_t length,
- u_char **error);
-static int bgp_msg_capability_mp (bgp_connection connection,
- struct capability_header *hdr);
-static int bgp_msg_capability_restart (bgp_connection connection,
- struct capability_header *caphdr);
-static int bgp_msg_capability_orf_entry (bgp_connection connection,
- struct capability_header *hdr);
-static int bgp_msg_capability_orf (bgp_connection connection,
- struct capability_header *hdr);
-static void bgp_msg_capability_orf_not_support (char *host, afi_t afi,
- safi_t safi, u_char type, u_char mode);
static int bgp_msg_update_receive (bgp_connection connection, bgp_size_t size);
static int bgp_msg_keepalive_receive (bgp_connection connection,
bgp_size_t size);
@@ -70,138 +51,169 @@ static void bgp_msg_notify_send_with_data (bgp_connection connection,
extern bgp_size_t
bgp_msg_get_mlen(uint8_t* p)
{
- return (*(p + BGP_MARKER_SIZE)) + (*(p + BGP_MARKER_SIZE + 1) << 8) ;
+ return (*(p + BGP_MH_MARKER_L)) + (*(p + BGP_MH_MARKER_L + 1) << 8) ;
} ;
-/* read and validate header.
- * return >= 0 number of bytes still to read
+
+/*------------------------------------------------------------------------------
+ * Header validation support.
+ */
+ /* 0 1 2 3 */
+static const uint8_t bgp_header[] = { 0xFF, 0xFF, 0xFF, 0xFF, /* 4 */
+ 0xFF, 0xFF, 0xFF, 0xFF, /* 8 */
+ 0xFF, 0xFF, 0xFF, 0xFF, /* 12 */
+ 0xFF, 0xFF, 0xFF, 0xFF /* 16 */
+ } ;
+CONFIRM(sizeof(bgp_header) == BGP_MH_MARKER_L) ;
+
+/* Array to return minimum message length.
+ *
+ * Length includes the header, so cannot possibly be zero !
+ */
+static const bgp_size_t bgp_type_min_size[256] =
+{
+ [BGP_MT_OPEN] = BGP_OPM_MIN_L,
+ [BGP_MT_UPDATE] = BGP_UPM_MIN_L,
+ [BGP_MT_NOTIFICATION] = BGP_NOM_MIN_L,
+ [BGP_MT_KEEPALIVE] = BGP_KAM_L,
+ [BGP_MT_ROUTE_REFRESH] = BGP_RRM_MIN_L,
+ [BGP_MT_CAPABILITY] = BGP_MH_HEAD_L, /* pro tem */
+ [BGP_MT_ROUTE_REFRESH_pre] = BGP_RRM_MIN_L
+} ;
+
+/*------------------------------------------------------------------------------
+ * The message size field is invalid per RFC
+ *
+ * Issue notification and kick FSM.
+ */
+static int
+bgp_msg_header_bad_len(bgp_connection connection, uint8_t type, bgp_size_t size)
+{
+ uint16_t notify_size = htons(size) ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ plog_debug (connection->log,
+ "%s bad message length - %d for %s",
+ connection->host, size,
+ type == 128 ? "ROUTE-REFRESH" : bgp_type_str[(int) type]) ;
+
+ bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg,
+ BGP_NOMC_HEADER, BGP_NOMS_H_BAD_LEN,
+ (void*)&notify_size, 2) ;
+ return -1 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Validate header part of BGP message.
+ *
+ * Have just read the header part (BGP_MH_HEAD_L) into connection->ibuf, need
+ * to check it's valid, and find how much more to read to complete the
+ * message.
+ *
+ * Advances the stream getp past the header.
+ *
+ * Plants: msg_type -- the message type
+ * msg_size -- the size of the message body
+ *
+ * in the connection, ready for bgp_msg_dispatch().
+ *
+ * return >= 0 number of bytes still to read (ie msg_size)
* return -1 error
*/
int
bgp_msg_check_header(bgp_connection connection)
{
- u_char type = 0;
- bgp_size_t size;
- char notify_data_length[2];
- bgp_session session = connection->session;
+ uint8_t type ;
+ bgp_size_t size ;
+ bgp_size_t min_size ;
- assert(session);
-
- /* Get size and type. */
- stream_forward_getp (connection->ibuf, BGP_MARKER_SIZE);
- memcpy (notify_data_length, stream_pnt (connection->ibuf), 2);
+ /* Get size and type. */
+ stream_forward_getp (connection->ibuf, BGP_MH_MARKER_L);
size = stream_getw (connection->ibuf);
type = stream_getc (connection->ibuf);
if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0)
zlog_debug ("%s rcv message type %d, length (excl. header) %d",
- session->host, type, size - BGP_HEADER_SIZE);
+ connection->host, type, size - BGP_MH_HEAD_L);
- /* Marker check */
- if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE))
- && ! bgp_msg_marker_all_one (connection->ibuf, BGP_MARKER_SIZE))
+ /* Marker check */
+ /* TODO: why did old code only do this on OPEN and KEEPALIVE ? */
+ if (memcmp(connection->ibuf->data, bgp_header, BGP_MH_MARKER_L) != 0)
{
bgp_msg_notify_send (connection, bgp_session_eInvalid_msg,
BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_NOT_SYNC);
return -1;
- }
+ } ;
+
+ /* BGP type check. */
+ min_size = bgp_type_min_size[type] ;
- /* BGP type check. */
- if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
- && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE
- && type != BGP_MSG_ROUTE_REFRESH_NEW
- && type != BGP_MSG_ROUTE_REFRESH_OLD
- && type != BGP_MSG_CAPABILITY)
+ if (min_size == 0)
{
if (BGP_DEBUG (normal, NORMAL))
- plog_debug (session->log,
+ plog_debug (connection->log,
"%s unknown message type 0x%02x",
- session->host, type);
- bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE,
- &type, 1);
- return -1;
- }
+ connection->host, type);
- /* Mimimum packet length check. */
- if ((size < BGP_HEADER_SIZE)
- || (size > BGP_MAX_PACKET_SIZE)
- || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE)
- || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE)
- || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE)
- || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE)
- || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
- || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
- || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE))
- {
- if (BGP_DEBUG (normal, NORMAL))
- plog_debug (session->log,
- "%s bad message length - %d for %s",
- session->host, size,
- type == 128 ? "ROUTE-REFRESH" :
- bgp_type_str[(int) type]);
bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESLEN,
- (u_char *) notify_data_length, 2);
+ BGP_NOMC_HEADER,
+ BGP_NOMS_H_BAD_TYPE,
+ &type, 1);
return -1;
- }
+ } ;
- return size - BGP_HEADER_SIZE;
-}
+ /* Mimimum and maximum message length checks. */
+ if ((size < min_size) || (size > BGP_MSG_MAX_L))
+ return bgp_msg_header_bad_len(connection, type, size) ;
-/* Marker check. */
-static int
-bgp_msg_marker_all_one (struct stream *s, int length)
-{
- int i;
-
- for (i = 0; i < length; i++)
- if (s->data[i] != 0xff)
- return 0;
+ connection->msg_type = type ;
+ connection->msg_size = size - BGP_MH_HEAD_L ;
- return 1;
+ return connection->msg_size ;
}
-/* Deal with the BGP message. MUST remove from ibuf before returns ! */
+/*------------------------------------------------------------------------------
+ * Dispatch BGP message.
+ *
+ * Arrives in the connection->ibuf, with the getp sitting after the message
+ * header. Also:
+ *
+ * connection->msg_type -- type
+ * connection->msg_size -- size of message body (excludes header)
+ *
+ * Must have finished with ibuf when returns.
+ */
void
bgp_msg_dispatch(bgp_connection connection)
{
- u_char type = 0;
- bgp_size_t size;
-
- /* Get size and type again. */
- size = stream_getw_from (connection->ibuf, BGP_MARKER_SIZE);
- type = stream_getc_from (connection->ibuf, BGP_MARKER_SIZE + 2);
-
- size -= BGP_HEADER_SIZE;
+ uint8_t type = connection->msg_size ;
+ bgp_size_t size = connection->msg_type ;
/* Read rest of the packet and call each sort of packet routine */
switch (type)
{
- case BGP_MSG_OPEN:
+ case BGP_MT_OPEN:
bgp_msg_open_receive (connection, size);
break;
- case BGP_MSG_UPDATE:
+ case BGP_MT_UPDATE:
bgp_msg_update_receive (connection, size);
break;
- case BGP_MSG_NOTIFY:
+ case BGP_MT_NOTIFICATION:
bgp_msg_notify_receive(connection, size);
break;
- case BGP_MSG_KEEPALIVE:
+ case BGP_MT_KEEPALIVE:
bgp_msg_keepalive_receive(connection, size);
break;
- case BGP_MSG_ROUTE_REFRESH_NEW:
- case BGP_MSG_ROUTE_REFRESH_OLD:
+ case BGP_MT_ROUTE_REFRESH:
+ case BGP_MT_ROUTE_REFRESH_pre:
/* TODO: refresh? */
#if 0
peer->refresh_in++;
bgp_route_refresh_receive (peer, size);
#endif
break;
- case BGP_MSG_CAPABILITY:
+ case BGP_MT_CAPABILITY:
/* TODO: dynamic capability? */
#if 0
peer->dynamic_cap_in++;
@@ -210,16 +222,32 @@ bgp_msg_dispatch(bgp_connection connection)
break;
default:
assert(0); /* types already validated */
- }
+ } ;
+} ;
- /* remove message from ibuf */
- if (connection->ibuf)
- stream_reset (connection->ibuf);
-}
+/*==============================================================================
+ * BGP OPEN message
+ *
+ *
+ *
+ */
+
+static int
+bgp_msg_open_option_parse (bgp_connection connection, bgp_notify notification,
+ sucker sr) ;
+static int
+bgp_msg_capability_option_parse (bgp_connection connection,
+ bgp_notify notification, sucker sr) ;
+static int
+bgp_msg_open_error(bgp_notify notification, bgp_nom_subcode_t subcode) ;
-/* Receive BGP open packet and parse it into the session's
- * open_recv
- * return 0 OK
+static int
+bgp_msg_open_invalid(bgp_notify notification) ;
+
+/*------------------------------------------------------------------------------
+ * Receive BGP open packet and parse it into the connection's open_recv
+ *
+ * return 0 OK
* return -1 error
*/
static int
@@ -228,822 +256,1029 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
int ret;
u_char version;
u_char optlen;
- as_t remote_as = 0;
- as_t as4 = 0;
struct in_addr remote_id;
- int capability;
- u_int8_t notify_data_remote_as[2];
- u_int8_t notify_data_remote_id[4];
- bgp_session session = connection->session;
bgp_open_state open_recv;
+ struct stream* s ;
+ struct sucker ssr ;
+ unsigned holdtime ;
+
+ /* Start with an unspecific OPEN notification */
+ bgp_notify notification = bgp_notify_new(BGP_NOMC_OPEN,
+ BGP_NOMS_UNSPECIFIC, 0) ;
- assert(session);
+ /* To receive the parsed open message */
+ open_recv = connection->open_recv
+ = bgp_open_state_init_new(connection->open_recv) ;
- /* To receive the parsed open message */
- session->open_recv = bgp_open_state_init_new(session->open_recv);
- open_recv = session->open_recv;
+ /* Parse fixed part of the open packet */
+ s = connection->ibuf ;
- /* Parse open packet. */
- version = stream_getc (connection->ibuf);
- memcpy (notify_data_remote_as, stream_pnt (connection->ibuf), 2);
- open_recv->my_as = stream_getw (connection->ibuf);
- open_recv->holdtime = stream_getw (connection->ibuf);
- memcpy (notify_data_remote_id, stream_pnt (connection->ibuf), 4);
- remote_id.s_addr = stream_get_ipv4 (connection->ibuf);
+ version = stream_getc (s);
+ open_recv->my_as2 = stream_getw (s);
+ open_recv->holdtime = stream_getw (s);
+ open_recv->bgp_id = stream_get_ipv4 (s);
- /* Receive OPEN message log */
+ open_recv->my_as = open_recv->my_as2 ;
+
+ remote_id.s_addr = open_recv->bgp_id ;
+
+ /* Receive OPEN message log */
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u,"
" holdtime %d, id %s",
- session->host, version, open_recv->my_as, open_recv->holdtime,
+ connection->host, version,
+ open_recv->my_as, open_recv->holdtime,
inet_ntoa (remote_id));
- /* BEGIN to read the capability here, but don't do it yet */
- capability = 0;
- optlen = stream_getc (connection->ibuf);
-
- if (optlen != 0)
+ /* Peer BGP version check. */
+ if (version != BGP_VERSION_4)
{
- /* We need the as4 capability value *right now* because
- * if it is there, we have not got the remote_as yet, and without
- * that we do not know which peer is connecting to us now.
- */
- as4 = bgp_msg_peek_for_as4_capability (connection, optlen);
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug("%s bad protocol version, remote requested %d, local max %d",
+ connection->host, version, BGP_VERSION_4);
+
+ bgp_msg_open_error(notification, BGP_NOMS_O_VERSION) ;
+ bgp_notify_append_w(notification, BGP_VERSION_4) ;
+
+ goto reject ;
}
- /* Just in case we have a silly peer who sends AS4 capability set to 0 */
- if (open_recv->can_as4 && !as4)
+ /* Remote bgp_id may not be multicast, or the same as here */
+ if (IN_MULTICAST(open_recv->bgp_id) ||
+ (open_recv->bgp_id == connection->session->open_send->bgp_id))
{
- zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0",
- session->host);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
- return -1;
- }
+ zlog_debug ("%s rcv OPEN, *multicast* id %s",
+ connection->host, inet_ntoa (remote_id)) ;
+ bgp_msg_noms_o_bad_id(notification, open_recv->bgp_id) ;
+ goto reject ;
+ } ;
+
+ /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST
+ calculate the value of the Hold Timer by using the smaller of its
+ configured Hold Time and the Hold Time received in the OPEN message.
+ The Hold Time MUST be either zero or at least three seconds. An
+ implementation may reject connections on the basis of the Hold Time.
+
+ See below where sets keepalive to hold / 3 !!
+ */
+ if (open_recv->holdtime < 3 && open_recv->holdtime != 0)
+ {
+ bgp_msg_open_error(notification, BGP_NOMS_O_H_TIME) ;
+ goto reject ;
+ } ;
+
+ /* Open option part parse */
+
+ optlen = stream_getc(s) ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
+ connection->host, optlen) ;
- if (remote_as == BGP_AS_TRANS)
+ if (optlen != stream_get_left(s))
{
- /* Take the AS4 from the capability. We must have received the
- * capability now! Otherwise we have a asn16 peer who uses
- * BGP_AS_TRANS, for some unknown reason.
- */
- if (as4 == BGP_AS_TRANS)
+ zlog_err ("%s bad OPEN, message length %u but option length %u",
+ connection->host, (unsigned)stream_get_endp(s), optlen) ;
+ bgp_msg_open_invalid(notification) ;
+ goto reject ;
+ } ;
+
+ suck_init(&ssr, stream_pnt(s), optlen) ;
+
+ ret = bgp_msg_open_option_parse (connection, notification, &ssr) ;
+ if (ret < 0)
+ goto reject ;
+
+ /* Now worry about the AS number */
+
+ /* ASN == 0 is odd for AS2, error for AS4 */
+ if (open_recv->my_as == 0)
+ {
+ if (open_recv->can_as4)
+ {
+ zlog_err ("%s [AS4] bad OPEN, got AS4 capability, but AS4 set to 0",
+ connection->host) ;
+ bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ;
+ goto reject ;
+ }
+ else
+ {
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("%s [AS4] OPEN remote_as is 0 (not AS4 speaker)"
+ " odd, but proceeding.", connection->host) ;
+ } ;
+ } ;
+
+ /* ASN = BGP_AS_TRANS is odd for AS2, error for AS4 */
+ if (open_recv->my_as == BGP_ASN_TRANS)
+ {
+ if (open_recv->can_as4)
{
zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed",
- session->host);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
- return -1;
+ connection->host);
+ bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ;
+ goto reject ;
}
-
- if (!as4 && BGP_DEBUG (as4, AS4))
- zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4."
- " Odd, but proceeding.", session->host);
- else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4))
- zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits "
- "in 2-bytes, very odd peer.", session->host, as4);
- if (as4)
- remote_as = as4;
- }
- else
+ else
+ {
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS (not AS4 speaker)"
+ " odd, but proceeding.", connection->host) ;
+ } ;
+ } ;
+
+ /* Worry about my_as2 for AS4 speaker, if as2 != as4 */
+ if ((open_recv->can_as4) && (open_recv->my_as != open_recv->my_as2))
{
- /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */
- /* If we have got the capability, peer->as4cap must match remote_as */
- if (open_recv->can_as4 && as4 != remote_as)
+ if (open_recv->my_as2 == BGP_ASN_TRANS)
+ {
+ if ((open_recv->my_as <= BGP_AS2_MAX) && BGP_DEBUG(as4, AS4))
+ zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS,"
+ " but AS4 (%u) fits in 2-bytes, very odd peer.",
+ connection->host, open_recv->my_as) ;
+ }
+ else
{
- /* raise error, log this, close session */
zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u"
" mismatch with 16bit 'myasn' %u in open",
- session->host, as4, remote_as);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
- return -1;
- }
- }
+ connection->host, open_recv->my_as, open_recv->my_as2) ;
- /* Set remote router-id */
- open_recv->bgp_id = remote_id.s_addr;
+ bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ;
+ goto reject ;
+ } ;
+ } ;
- /* Peer BGP version check. */
- if (version != BGP_VERSION_4)
- {
- u_int8_t maxver = BGP_VERSION_4;
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad protocol version, remote requested %d, local request %d",
- session->host, version, BGP_VERSION_4);
- bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_VERSION,
- &maxver, 1);
- return -1;
- }
-
- /* TODO: How? Check neighbor as number. */
-#if 0
- if (remote_as != session->as)
+ /* Finally -- require the AS to be the configured AS */
+ if (open_recv->my_as != connection->session->as_expected)
{
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- session->host, remote_as, session->as);
- bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS,
- notify_data_remote_as, 2);
- return -1;
- }
-#endif
+ connection->host, open_recv->my_as,
+ connection->session->as_expected) ;
- /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST
- calculate the value of the Hold Timer by using the smaller of its
- configured Hold Time and the Hold Time received in the OPEN message.
- The Hold Time MUST be either zero or at least three seconds. An
- implementation may reject connections on the basis of the Hold Time. */
-
- if (open_recv->holdtime < 3 && open_recv->holdtime != 0)
- {
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
- return -1;
- }
+ bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ;
+ if (open_recv->can_as4)
+ bgp_notify_append_l(notification, open_recv->my_as) ;
+ else
+ bgp_notify_append_w(notification, open_recv->my_as) ;
- /* Open option part parse. */
- if (optlen != 0)
- {
- ret = bgp_msg_open_option_parse (connection, optlen, &open_recv->can_capability);
- if (ret < 0)
- return ret;
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0",
- session->host);
+ goto reject ;
}
- bgp_fsm_event(connection, bgp_fsm_Receive_OPEN_message);
+ /*............................................................................
+ * It's OK ! Update the connection and issue event.
+ */
+ bgp_notify_free(notification) ; /* No further use for this */
- return 0;
-}
+ holdtime = connection->session->open_send->holdtime ;
-static as_t
-bgp_msg_capability_as4 (bgp_connection connection, struct capability_header *hdr)
-{
- as_t as4 = stream_getl (connection->ibuf);
- bgp_session session = connection->session;
- assert(session);
+ if (holdtime > open_recv->holdtime)
+ holdtime = open_recv->holdtime ; /* use smaller of theirs & ours */
+ if (holdtime < 3)
+ holdtime = 0 ; /* no slip ups */
- if (BGP_DEBUG (as4, AS4))
- zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
- session->host, as4);
+ connection->hold_timer_interval = holdtime ;
+ connection->keepalive_timer_interval = holdtime / 3 ;
- return as4;
-}
+ connection->as4 = open_recv->can_as4 ;
+ connection->route_refresh_pre = open_recv->can_r_refresh == bgp_cap_form_old;
+ connection->orf_prefix_pre = open_recv->can_orf_prefix == bgp_cap_form_old;
-/* peek into option, stores ASN to *as4 if the AS4 capability was found.
- * Returns 0 if no as4 found, as4cap value otherwise.
- */
-static as_t
-bgp_msg_peek_for_as4_capability (bgp_connection connection, u_char length)
-{
- struct stream *s = connection->ibuf;
- size_t orig_getp = stream_get_getp (s);
- size_t end = orig_getp + length;
- as_t as4 = 0;
- bgp_session session = connection->session;
- assert(session);
+ bgp_fsm_event(connection, bgp_fsm_Receive_OPEN_message) ;
- /* The full capability parser will better flag the error.. */
- if (STREAM_READABLE(s) < length)
- return 0;
+ return 0;
- if (BGP_DEBUG (as4, AS4))
- zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
- " peeking for as4",
- session->host, length);
- /* the error cases we DONT handle, we ONLY try to read as4 out of
- * correctly formatted options.
+ /*............................................................................
+ * Failed. Reject the OPEN with the required notification.
*/
- while (stream_get_getp(s) < end)
- {
- u_char opt_type;
- u_char opt_length;
+reject:
+ bgp_fsm_raise_exception(connection, bgp_session_eOpen_reject, notification);
- /* Check the length. */
- if (stream_get_getp (s) + 2 > end)
- goto end;
-
- /* Fetch option type and length. */
- opt_type = stream_getc (s);
- opt_length = stream_getc (s);
-
- /* Option length check. */
- if (stream_get_getp (s) + opt_length > end)
- goto end;
-
- if (opt_type == BGP_OPEN_OPT_CAP)
- {
- unsigned long capd_start = stream_get_getp (s);
- unsigned long capd_end = capd_start + opt_length;
+ return -1 ;
+} ;
- assert (capd_end <= end);
+/*------------------------------------------------------------------------------
+ * Set notification to BGP_NOMC_OPEN/BGP_NOMS_O_BAD_ID and set the data part
+ * to be the given bad id.
+ *
+ * Create notification if required.
+ */
+extern bgp_notify
+bgp_msg_noms_o_bad_id(bgp_notify notification, bgp_id_t id)
+{
+ notification = bgp_notify_reset(notification, BGP_NOMC_OPEN,
+ BGP_NOMS_O_BAD_ID) ;
+ bgp_notify_append_data(notification, &id, 4) ;
- while (stream_get_getp (s) < capd_end)
- {
- struct capability_header hdr;
+ return notification ;
+} ;
- if (stream_get_getp (s) + 2 > capd_end)
- goto end;
+/*------------------------------------------------------------------------------
+ * Reset notification to BGP_NOMC_OPEN with the given subcode, and return -1.
+ */
+static int
+bgp_msg_open_error(bgp_notify notification, bgp_nom_subcode_t subcode)
+{
+ bgp_notify_reset(notification, BGP_NOMC_OPEN, subcode) ;
+ return -1 ;
+} ;
- hdr.code = stream_getc (s);
- hdr.length = stream_getc (s);
+/*------------------------------------------------------------------------------
+ * Reset notification to BGP_NOMC_OPEN/BGP_NOMS_UNSPECIFIC, and return -1.
+ */
+static int
+bgp_msg_open_invalid(bgp_notify notification)
+{
+ return bgp_msg_open_error(notification, BGP_NOMS_UNSPECIFIC) ;
+} ;
- if ((stream_get_getp(s) + hdr.length) > capd_end)
- goto end;
+/*------------------------------------------------------------------------------
+ * Add unsupported capability to notification.
+ *
+ * The sr points at the start of the capability value.
+ */
+static void
+bgp_msg_capability_unsupported(bgp_notify notification, sucker sr)
+{
+ ptr_t p_cap ;
+ int cap_len ;
- if (hdr.code == CAPABILITY_CODE_AS4)
- {
- if (hdr.length != CAPABILITY_CODE_AS4_LEN)
- goto end;
+ if (notification->subcode != BGP_NOMS_O_CAPABILITY)
+ bgp_notify_reset(notification, BGP_NOMC_OPEN, BGP_NOMS_O_CAPABILITY) ;
- if (BGP_DEBUG (as4, AS4))
- zlog_info ("[AS4] found AS4 capability, about to parse");
- as4 = stream_getl (connection->ibuf);
- session->open_recv->can_as4 = 1;
+ cap_len = suck_total(sr) ;
+ p_cap = suck_start(sr) - BGP_CAP_MIN_L ;
- goto end;
- }
- stream_forward_getp (s, hdr.length);
- }
- }
- }
+ assert(*(p_cap + 1) == cap_len) ;
-end:
- stream_set_getp (s, orig_getp);
- return as4;
-}
+ bgp_notify_append_data(notification, p_cap, BGP_CAP_MIN_L + cap_len) ;
+} ;
-/* Parse open option */
+/*------------------------------------------------------------------------------
+ * Parse OPEN message options part.
+ *
+ * Expects the notification to be set up: BGP_NOMC_OPEN, BGP_NOMS_UNSPECIFIC
+ * with no data, yet.
+ *
+ * Returns: -1 => error -- see notification
+ * 0 => OK, no capabilities
+ * 1 => OK, at least one capability
+ */
static int
-bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capability)
+bgp_msg_open_option_parse (bgp_connection connection, bgp_notify notification,
+ sucker sr)
{
- int ret;
- u_char *error;
- u_char error_data[BGP_MAX_PACKET_SIZE];
- struct stream *s = connection->ibuf;
- size_t end = stream_get_getp (s) + length;
- bgp_session session = connection->session;
- assert(session);
+ int ret, capability ;
+ int left ;
+ bgp_session session = connection->session ;
+ bgp_open_state open_send = session->open_send ;
+ bgp_open_state open_recv = connection->open_recv ;
- ret = 0;
- error = error_data;
+ /* Prepare to read BGP OPEN message options */
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
- session->host, length);
+ ret = 0 ; /* OK so far */
+ capability = 0 ; /* No capability option, yet */
- while (stream_get_getp(s) < end)
+ while ((left = suck_left(sr)) > 0)
{
- u_char opt_type;
- u_char opt_length;
+ struct sucker ssr ;
+ u_char opt_type ;
+ u_char opt_length ;
- /* Must have at least an OPEN option header */
- if (STREAM_READABLE(s) < 2)
+ /* Fetch option type and length, if possible */
+ if ((left -= 2) > 0)
{
- zlog_info ("%s Option length error", session->host);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_CEASE, 0);
- return -1;
- }
+ opt_type = suck_b(sr);
+ opt_length = suck_b(sr);
+ left -= opt_length ;
+ } ;
- /* Fetch option type and length. */
- opt_type = stream_getc (s);
- opt_length = stream_getc (s);
-
- /* Option length check. */
- if (STREAM_READABLE (s) < opt_length)
+ /* Must not have exceeded available bytes */
+ if (left < 0)
{
- zlog_info ("%s Option length error", session->host);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_CEASE, 0);
- return -1;
+ zlog_info ("%s Option length error", connection->host);
+ return bgp_msg_open_invalid(notification) ;
}
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
- session->host, opt_type,
+ connection->host, opt_type,
opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
opt_length);
+ suck_push(sr, opt_length, &ssr) ;
+
switch (opt_type)
{
- case BGP_OPEN_OPT_AUTH:
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_AUTH_FAILURE);
- ret = -1;
- break;
- case BGP_OPEN_OPT_CAP:
- ret = bgp_msg_capability_parse (connection, opt_length, &error);
- *capability = 1;
+ case BGP_OPT_AUTH:
+ return bgp_msg_open_error(notification, BGP_NOMS_O_AUTH) ;
+
+ case BGP_OPT_CAPS:
+ capability = 1 ; /* does => can */
+
+ ret = bgp_msg_capability_option_parse(connection, notification, sr) ;
+ if (ret < 0)
+ return bgp_msg_open_invalid(notification) ;
+
break;
+
default:
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_PARAM);
- ret = -1;
- break;
- }
+ return bgp_msg_open_error(notification, BGP_NOMS_O_OPTION) ;
+ } ;
+
+ suck_pop(sr, &ssr) ;
+ } ;
+
+ /* All OPEN option is parsed.
+ *
+ * Do "strict" capability checks:
+ *
+ * 1) if there were any unknown capabilities, or any AFI/SAFI which are
+ * unknown or are not configured, then that is now an error.
+ *
+ * 2) the local AFI/SAFI must be the same as the remote AFI/SAFI.
+ *
+ * TODO: verify that (2) should be checked *before* any "OVERRIDE".
+ */
+ if (session->cap_strict)
+ {
+ /* Treat any unsuppprted capability as an error. */
+ if (bgp_notify_get_subcode(notification) == BGP_NOMS_O_CAPABILITY)
+ return -1 ;
- /* Parse error. To accumulate all unsupported capability codes,
- bgp_capability_parse does not return -1 when encounter
- unsupported capability code. To detect that, please check
- error and erro_data pointer, like below. */
- if (ret < 0)
- return -1;
- }
+ /* Check local AFI/SAFI set is same as the remote one. */
+ if (open_recv->can_mp_ext != open_send->can_mp_ext)
+ return bgp_msg_open_error(notification, BGP_NOMS_O_CAPABILITY) ;
+ } ;
- /* All OPEN option is parsed. Check capability when strict compare
- flag is enabled.*/
- if (session->cap_strict)
+ /* If there were any capabilities, and not going to override AFI/SAFI,
+ * then check that there is at least one AFI/SAFI in common.
+ */
+ if (capability && ! session->cap_override)
{
- /* If Unsupported Capability exists. */
- if (error != error_data)
+ if ((open_recv->can_mp_ext & open_send->can_mp_ext) == 0)
{
- bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data, error - error_data);
- return -1;
- }
+ plog_err (connection->log, "%s [Error] No common capability",
+ connection->host) ;
+ if (bgp_notify_get_subcode(notification) != BGP_NOMS_O_CAPABILITY)
+ bgp_msg_open_error(notification, BGP_NOMS_O_CAPABILITY) ;
- /* Check local capability does not negotiated with remote
- peer. */
- if (session->open_recv->can_mp_ext != session->open_send->can_mp_ext)
- {
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
- return -1;
+ return -1 ;
}
- }
+ } ;
- /* Check there is no common capability send Unsupported Capability
- error. */
- if (*capability && ! session->cap_override)
- {
- if (session->open_recv->can_mp_ext == 0)
- {
- plog_err (session->log, "%s [Error] No common capability", session->host);
+ return connection->open_recv->can_capability = capability ;
+} ;
- if (error != error_data)
+/*------------------------------------------------------------------------------
+ * From IANA "Capability Codes (last updated 2009-08-04) Reference: [RFC5492]"
+ *
+ * Range Registration Procedures
+ * --------- --------------------------
+ * 1- 63 IETF Review
+ * 64-127 First Come First Served
+ * 128-255 Reserved for Private Use (IANA does not assign)
+ *
+ * 1 Multiprotocol Extensions for BGP-4 [RFC2858]
+ * 2 Route Refresh Capability for BGP-4 [RFC2918]
+ * 3 Outbound Route Filtering Capability [RFC5291]
+ * 4 Multiple routes to a destination capability [RFC3107]
+ * 5 Extended Next Hop Encoding [RFC5549]
+ * 64 Graceful Restart Capability [RFC4724]
+ * 65 Support for 4-octet AS number capability [RFC4893]
+ * 66 Deprecated (2003-03-06)
+ * 67 Support for Dynamic Capability (capability specific) [Chen]
+ * 68 Multisession BGP Capability [Appanna]
+ * 69 ADD-PATH Capability [draft-ietf-idr-add-paths]
+ *
+ * 66 is, in fact, for draft-ietf-idr-dynamic-cap-02 of the Support for
+ * Dynamic Capability (capability specific)
+ *
+ * Supported:
+ *
+ * 1 BGP_CAN_MP_EXT -- Multiprotocol Extensions
+ * 2 BGP_CAN_R_REFRESH -- Route Refresh
+ * 3 BGP_CAN_ORF -- Outbound Route Filtering
+ * 64 BGP_CAN_G_RESTART -- Graceful Restart
+ * 65 BGP_CAN_AS4 -- AS4
+ * 66 BGP_CAN_DYNAMIC_CAP_old -- Dynamic Capability (old form)
+ * 128 BGP_CAN_R_REFRESH_pre -- pre-RFC Route Refresh
+ * 130 BGP_CAN_ORF_pre -- pre-RFC Outbound Route Filtering
+ */
- bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data, error - error_data);
- else
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
- return -1;
- }
- }
- return 0;
-}
+CONFIRM(BGP_CAP_MPE_L == sizeof (struct capability_mp_data)) ;
+CONFIRM(BGP_CAP_RRF_L == CAPABILITY_CODE_REFRESH_LEN) ;
+CONFIRM(BGP_CAP_ORFE_MIN_L == sizeof (struct capability_orf_entry)) ;
+CONFIRM(BGP_CAP_GR_MIN_L == sizeof (struct capability_gr)) ;
+CONFIRM(BGP_CAP_AS4_L == CAPABILITY_CODE_AS4_LEN) ;
+CONFIRM(BGP_CAP_DYN_L == CAPABILITY_CODE_DYNAMIC_LEN) ;
+
+CONFIRM(BGP_CAN_MP_EXT == CAPABILITY_CODE_MP) ;
+CONFIRM(BGP_CAN_R_REFRESH == CAPABILITY_CODE_REFRESH) ;
+CONFIRM(BGP_CAN_ORF == CAPABILITY_CODE_ORF) ;
+CONFIRM(BGP_CAN_G_RESTART == CAPABILITY_CODE_RESTART) ;
+CONFIRM(BGP_CAN_AS4 == CAPABILITY_CODE_AS4) ;
+CONFIRM(BGP_CAN_DYNAMIC_CAP_old == CAPABILITY_CODE_DYNAMIC) ;
+CONFIRM(BGP_CAN_R_REFRESH_pre == CAPABILITY_CODE_REFRESH_OLD) ;
+CONFIRM(BGP_CAN_ORF_pre == CAPABILITY_CODE_ORF_OLD) ;
+
+/* TODO: clarify value for BGP_CAN_DYNAMIC_CAP !! */
+
+/* Minimum sizes for length field of each cap (so not inc. the header) */
+static const unsigned cap_minsizes[] =
+{
+ [BGP_CAN_MP_EXT] = BGP_CAP_MPE_L,
+ [BGP_CAN_R_REFRESH] = BGP_CAP_RRF_L,
+ [BGP_CAN_ORF] = BGP_CAP_ORFE_MIN_L,
+ [BGP_CAN_G_RESTART] = BGP_CAP_GR_MIN_L,
+ [BGP_CAN_AS4] = BGP_CAP_AS4_L,
+ [BGP_CAN_DYNAMIC_CAP_old] = BGP_CAP_DYN_L,
+ [BGP_CAN_DYNAMIC_CAP] = BGP_CAP_DYN_L,
+ [BGP_CAN_R_REFRESH_pre] = BGP_CAP_RRF_L,
+ [BGP_CAN_ORF_pre] = BGP_CAP_ORFE_MIN_L,
+} ;
+
+static const unsigned cap_maxsizes[] =
+{
+ [BGP_CAN_MP_EXT] = BGP_CAP_MPE_L,
+ [BGP_CAN_R_REFRESH] = BGP_CAP_RRF_L,
+ [BGP_CAN_ORF] = BGP_CAP_MAX_L, /* variable */
+ [BGP_CAN_G_RESTART] = BGP_CAP_MAX_L, /* variable */
+ [BGP_CAN_AS4] = BGP_CAP_AS4_L,
+ [BGP_CAN_DYNAMIC_CAP_old] = BGP_CAP_DYN_L,
+ [BGP_CAN_DYNAMIC_CAP] = BGP_CAP_DYN_L,
+ [BGP_CAN_R_REFRESH_pre] = BGP_CAP_RRF_L,
+ [BGP_CAN_ORF_pre] = BGP_CAP_MAX_L, /* variable */
+} ;
+
+/* Forward references for parsing individual capabilities, return -1 if the
+ * capability is malformed or contains invalid values.
+ */
+static int
+bgp_msg_capability_mp(bgp_connection connection, sucker sr) ;
+
+static int
+bgp_msg_capability_orf (bgp_connection connection, uint8_t cap_code, sucker sr);
+
+static int
+bgp_msg_capability_restart (bgp_connection connection, sucker sr) ;
-/* Parse given capability.
- * XXX: This is reading into a stream, but not using stream API
+static int
+bgp_msg_capability_as4 (bgp_connection connection, sucker sr) ;
+
+/*------------------------------------------------------------------------------
+ * Set notification to malformed/invalid.
+ *
+ * Returns -1 !
*/
static int
-bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **error)
+bgp_msg_capability_bad(bgp_notify notification)
{
- int ret;
- struct stream *s = connection->ibuf;
- size_t end = stream_get_getp (s) + length;
- bgp_session session = connection->session;
- bgp_open_state open_recv = session->open_recv;
+ bgp_notify_reset(notification, BGP_NOMC_OPEN, BGP_NOMS_UNSPECIFIC) ;
+ return -1 ;
+} ;
- assert (STREAM_READABLE (s) >= length);
+/*------------------------------------------------------------------------------
+ * Parse given capability option -- may contain multiple capabilities.
+ *
+ * Adjusts the open_recv open state according to the capabilities seen.
+ *
+ * Collects unsupported capabilities in the notification, where a
+ * BGP_NOMS_O_CAPABILITY message will be created. So, at the end of the
+ * process, can tell if there are any unsupported capabilities.
+ *
+ * The unsupported capabilities will be:
+ *
+ * * MP Extensions AFI/SAFI which are unknown or are not configured at
+ * this end.
+ *
+ * * any unknown capabilities < 128
+ *
+ * If an invalid or malformed capability is found, the notification is set
+ * BGP_NOMS_UNSPECIFIC -- see bgp_msg_capability_bad() above.
+ *
+ * Returns: 0 => OK (but may have collected some unsupported capabilities)
+ * -1 => invalid or malformed
+ */
+static int
+bgp_msg_capability_option_parse (bgp_connection connection,
+ bgp_notify notification, sucker sr)
+{
+ int ret, left ;
+ bgp_open_state open_recv = connection->open_recv ;
- while (stream_get_getp (s) < end)
+ while ((left = suck_left(sr)) > 0)
{
- size_t start;
- u_char *sp = stream_pnt (s);
- struct capability_header caphdr;
+ struct sucker ssr ;
+ int cap_code ;
+ unsigned cap_length ;
/* We need at least capability code and capability length. */
- if (stream_get_getp(s) + 2 > end)
+ if ((left -= 2) > 0)
{
- zlog_info ("%s Capability length error (< header)", session->host);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_CEASE, 0);
- return -1;
+ cap_code = suck_b(sr);
+ cap_length = suck_b(sr);
+ left -= cap_length ;
}
- 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)
+ if (left < 0)
{
- zlog_info ("%s Capability length error (< length)", session->host);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_CEASE, 0);
- return -1;
- }
+ zlog_info ("%s Capability length error (< header)", connection->host);
+ return bgp_msg_capability_bad(notification) ;
+ } ;
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s OPEN has %s capability (%u), length %u",
- session->host,
- LOOKUP (capcode_str, caphdr.code),
- caphdr.code, caphdr.length);
+ connection->host,
+ LOOKUP (capcode_str, cap_code),
+ cap_code, cap_length) ;
/* Length sanity check, type-specific, for known capabilities */
- switch (caphdr.code)
+ switch (cap_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_AS4:
- case CAPABILITY_CODE_DYNAMIC:
+ case BGP_CAN_MP_EXT:
+ case BGP_CAN_R_REFRESH:
+ case BGP_CAN_ORF:
+ case BGP_CAN_G_RESTART:
+ case BGP_CAN_AS4:
+ case BGP_CAN_DYNAMIC_CAP:
+ case BGP_CAN_R_REFRESH_pre:
+ case BGP_CAN_ORF_pre:
/* Check length. */
- if (caphdr.length < cap_minsizes[caphdr.code])
+ if ( (cap_length < cap_minsizes[cap_code]) ||
+ (cap_length > cap_maxsizes[cap_code]) )
{
+ const char* tag = "" ;
+ if (cap_minsizes[cap_code] != cap_maxsizes[cap_code])
+ tag = "at least " ;
zlog_info ("%s %s Capability length error: got %u,"
- " expected at least %u",
- session->host,
- LOOKUP (capcode_str, caphdr.code),
- caphdr.length,
- (unsigned) cap_minsizes[caphdr.code]);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_CEASE, 0);
- return -1;
- }
+ " expected %s%u",
+ connection->host,
+ LOOKUP (capcode_str, cap_code),
+ cap_length, tag,
+ (unsigned) cap_minsizes[cap_code]) ;
+ return bgp_msg_capability_bad(notification) ;
+ /* invalid: stop dead */
+ } ;
+ break ;
/* we deliberately ignore unknown codes, see below */
default:
- break;
- }
+ break ;
+ } ;
+
+ /* By this point the capability length is exactly right for the
+ * fixed length capabilities, at least the minimum length for the rest.
+ * Also, then capability fits within the capability option.
+ */
+ suck_push(sr, cap_length, &ssr) ;
- switch (caphdr.code)
+ ret = 0 ;
+ switch (cap_code)
{
- case CAPABILITY_CODE_MP:
- {
- /* Ignore capability when override-capability is set. */
- if (! session->cap_override)
- {
- /* Set negotiated value. */
- ret = bgp_msg_capability_mp (connection, &caphdr);
-
- /* Unsupported Capability. */
- if (ret < 0)
- {
- /* Store return data. */
- memcpy (*error, sp, caphdr.length + 2);
- *error += caphdr.length + 2;
- }
- }
- }
+ case BGP_CAN_MP_EXT:
+ /* Ignore capability when override-capability is set.
+ *
+ * NB: bgp_msg_capability_mp() returns > 0 if the AFI/SAFI is not
+ * recognised or is not one of the configured ones.
+ */
+ if (! connection->session->cap_override)
+ ret = bgp_msg_capability_mp(connection, sr);
break;
- case CAPABILITY_CODE_REFRESH:
- case CAPABILITY_CODE_REFRESH_OLD:
- {
- /* BGP refresh capability */
- if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
- open_recv->can_r_refresh |= bgp_cap_form_old;
- else
- open_recv->can_r_refresh |= bgp_cap_form_new;
- }
+
+ case BGP_CAN_R_REFRESH:
+ open_recv->can_r_refresh |= bgp_cap_form_new ;
+ break ;
+
+ case BGP_CAN_R_REFRESH_pre:
+ open_recv->can_r_refresh |= bgp_cap_form_old;
break;
- case CAPABILITY_CODE_ORF:
- case CAPABILITY_CODE_ORF_OLD:
- if (bgp_msg_capability_orf (connection, &caphdr))
- return -1;
+
+ case BGP_CAN_ORF:
+ case BGP_CAN_ORF_pre:
+ ret = bgp_msg_capability_orf(connection, cap_code, sr) ;
break;
- case CAPABILITY_CODE_RESTART:
- if (bgp_msg_capability_restart (connection, &caphdr))
- return -1;
+
+ case BGP_CAN_G_RESTART:
+ ret = bgp_msg_capability_restart(connection, sr) ;
break;
- case CAPABILITY_CODE_DYNAMIC:
+
+ case BGP_CAN_DYNAMIC_CAP_old:
open_recv->can_dynamic = 1;
break;
- case CAPABILITY_CODE_AS4:
- /* Already handled as a special-case parsing of the capabilities
- * at the beginning of OPEN processing. So we care not a jot
- * for the value really, only error case.
- */
- if (!bgp_msg_capability_as4 (connection, &caphdr))
- return -1;
- break;
+
+ case BGP_CAN_AS4:
+ ret = bgp_msg_capability_as4(connection, sr) ;
+ break;
+
default:
- if (caphdr.code > 128)
+ 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",
- session->host, caphdr.code);
+ connection->host, cap_code);
}
else
{
zlog_warn ("%s unrecognized capability code: %d - ignored",
- session->host, caphdr.code);
- memcpy (*error, sp, caphdr.length + 2);
- *error += caphdr.length + 2;
+ connection->host, cap_code) ;
+ ret = 1 ; /* collect unsupported capability */
}
/* Add given unknown capability and its value */
- bgp_open_state_unknown_add(open_recv, caphdr.code,
- stream_pnt (s), caphdr.length);
+ bgp_open_state_unknown_add(open_recv, cap_code,
+ suck_start(sr), suck_total(sr)) ;
}
- 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!",
- session->host, LOOKUP (capcode_str, caphdr.code),
- caphdr.length);
- stream_set_getp (s, start + caphdr.length);
- }
+
+ if (ret < 0)
+ return bgp_msg_capability_bad(notification) ;
+
+ if (ret > 0)
+ bgp_msg_capability_unsupported(notification, sr) ;
+
+ suck_pop(sr, &ssr) ;
}
- return 0;
-}
-/* Set negotiated capability value. */
-static int
-bgp_msg_capability_mp (bgp_connection connection, struct capability_header *hdr)
+ return 0 ;
+} ;
+
+static qafx_bit_t
+bgp_msg_afi_safi(sucker sr, struct iAFI_SAFI* mp)
{
- struct capability_mp_data mpc;
- struct stream *s = connection->ibuf;
- bgp_session session = connection->session;
- bgp_open_state open_recv = session->open_recv;
- bgp_open_state open_send = session->open_send;
- qafx_bit_t qb;
+ mp->afi = suck_w(sr) ;
+ suck_x(sr) ;
+ mp->safi = suck_b(sr) ;
+
+ return qafx_bit_from_iAFI_iSAFI(mp->afi, mp->safi) ;
+} ;
- assert(session);
+/*------------------------------------------------------------------------------
+ * Process value of Multiprotocol Extensions -- BGP_CAN_MP_EXT -- RFC2858
+ *
+ * Capability is: AFI -- word
+ * reserved -- byte
+ * SAFI -- byte
+ *
+ * This is a fixed length capability, so that's been dealt with.
+ *
+ * Treats: invalid AFI/SAFI combinations )
+ * unknown AFI/SAFI combinations ) unsupported capability
+ * unsupported AFI/SAFI combinations )
+ *
+ * Sets any known AFI/SAFI combination in open_recv->can_mp_ext.
+ *
+ * Returns: 0 => OK -- AFI/SAFI is in the open_sent set
+ * 1 => -- AFI/SAFI is known, but not in the open_sent set
+ * 2 => -- AFI/SAFI is not known, may be invalid
+ */
+static int
+bgp_msg_capability_mp(bgp_connection connection, sucker sr)
+{
+ struct iAFI_SAFI mp ;
+ qafx_bit_t qb ;
- bgp_capability_mp_data (s, &mpc);
+ qb = bgp_msg_afi_safi(sr, &mp) ;
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
- session->host, mpc.afi, mpc.safi);
+ connection->host, mp.afi, mp.safi) ;
- if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
- return -1;
+ if (qb == 0)
+ {
+ zlog_warn ("Unknown afi/safi combination (%u/%u)", mp.afi, mp.safi) ;
+ return 2 ;
+ } ;
- /* Now safi remapped, and afi/safi are valid array indices */
- qb = qafx_bit(qafx_num_from_qAFI_qSAFI(mpc.afi, mpc.safi));
+ /* Now can register the capability */
+ connection->open_recv->can_mp_ext |= qb;
- open_recv->can_mp_ext |= qb;
+ /* Return: 0 => is in the open_send set
+ * 1 => is not
+ */
+ return ((connection->session->open_send->can_mp_ext & qb) != 0) ? 0 : 1 ;
+} ;
- /* won't negotiate on afi/safi? */
- if ((open_send->can_mp_ext & qb) == 0)
- return -1;
+/*------------------------------------------------------------------------------
+ * Process value of Outbound Route Filtering -- BGP_CAN_ORF -- RFC5291
+ *
+ * Must have at least one ORF Entry, but may have several and each is of
+ * variable length.
+ *
+ * Requirement for at least one entry has already been checked.
+ *
+ * Returns: 0 => OK
+ * -1 => malformed !
+ *
+ * NB: treats multiple ORF capabilities and multiple entries as additive.
+ * Does not track what AFI/SAFI and ORF types have been declared.
+ */
- return 0;
-}
+static int bgp_msg_capability_orf_entry(bgp_connection connection,
+ uint8_t cap_code, sucker sr) ;
static int
-bgp_msg_capability_restart (bgp_connection connection, struct capability_header *caphdr)
+bgp_msg_capability_orf(bgp_connection connection, uint8_t cap_code, sucker sr)
{
- struct stream *s = connection->ibuf;
- bgp_session session = connection->session;
- bgp_open_state open_recv = session->open_recv;
- bgp_open_state open_send = session->open_send;
- u_int16_t restart_flag_time;
- int restart_bit = 0;
- size_t end = stream_get_getp (s) + caphdr->length;
-
- open_recv->can_g_restart = 1;
- restart_flag_time = stream_getw(s);
- if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
- restart_bit = 1;
- UNSET_FLAG (restart_flag_time, 0xF000);
- open_recv->restart_time = restart_flag_time;
-
- if (BGP_DEBUG (normal, NORMAL))
- {
- zlog_debug ("%s OPEN has Graceful Restart capability", session->host);
- zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
- session->host, restart_bit ? " " : " not ",
- open_recv->restart_time);
- }
-
- while (stream_get_getp (s) + 4 < end)
+ while (suck_left(sr) > 0)
{
- 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 (suck_left(sr) < BGP_CAP_ORFE_MIN_L)
{
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
- " Ignore the Graceful Restart capability",
- session->host, afi, safi);
- }
- else
- {
- qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
-
- if (!(open_send->can_mp_ext & qb))
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
- " Ignore the Graceful Restart capability",
- session->host, afi, safi);
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Address family %s is%spreserved", session->host,
- afi_safi_print (afi, safi),
- CHECK_FLAG (flag, RESTART_F_BIT)
- ? " " : " not ");
-
- open_recv->can_preserve |= qb;
- if (CHECK_FLAG (flag, RESTART_F_BIT))
- open_recv->has_preserved |= qb;
- }
- }
- }
+ zlog_info ("%s ORF Capability length error,"
+ " Cap length left %u",
+ connection->host, suck_left(sr)) ;
+ return -1;
+ } ;
- return 0;
-}
+ if (bgp_msg_capability_orf_entry (connection, cap_code, sr) == -1)
+ return -1;
+ } ;
+ return 0;
+} ;
+/* Process ORF Entry:
+ *
+ * Entry is: AFI -- word
+ * reserved -- byte
+ * SAFI -- byte
+ * number -- byte
+ * type -- byte ) repeated "number" times
+ * send/recv -- byte )
+ *
+ * Returns: 0 => OK
+ * -1 => malformed
+ */
static int
-bgp_msg_capability_orf_entry (bgp_connection connection, struct capability_header *hdr)
+bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code,
+ sucker sr)
{
- struct stream *s = connection->ibuf;
- struct capability_orf_entry entry;
- afi_t afi;
- safi_t safi;
- u_char type;
- u_char mode;
- int i;
- bgp_session session = connection->session;
- qafx_bit_t qb;
-
- assert(session);
-
- /* ORF Entry header */
- bgp_capability_mp_data (s, &entry.mpc);
- entry.num = stream_getc (s);
- afi = entry.mpc.afi;
- safi = entry.mpc.safi;
+ iAFI_SAFI_t mp ;
+ int number ;
+ int length ;
+ sucker_t ssr ;
+
+ bgp_open_state open_recv = connection->open_recv ;
+ qafx_bit_t qb ;
+
+ /* ORF Entry header */
+ qb = bgp_msg_afi_safi(sr, &mp) ;
+ number = suck_b(sr) ;
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
- session->host, entry.mpc.afi, entry.mpc.safi);
+ zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u %d types",
+ connection->host, mp.afi, mp.safi, number) ;
- /* Check AFI and SAFI. */
- if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
- {
- zlog_info ("%s Addr-family %d/%d not supported."
- " Ignoring the ORF capability",
- session->host, entry.mpc.afi, entry.mpc.safi);
- return 0;
- }
+ /* Check AFI and SAFI. */
+ if (qb == 0)
+ zlog_info ("%s Addr-family %d/%d not known."
+ " Ignoring the ORF capability",
+ connection->host, mp.afi, mp.safi) ;
- /* validate number field */
- if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
+ /* Validate number field */
+ length = number * BGP_CAP_ORFT_L ;
+
+ if (suck_left(sr) < length)
{
zlog_info ("%s ORF Capability entry length error,"
- " Cap length %u, num %u",
- session->host, hdr->length, entry.num);
- bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
- BGP_NOTIFY_CEASE, 0);
+ " Cap length left %u, num %u",
+ connection->host, suck_left(sr), number) ;
return -1;
- }
+ } ;
+
+ /* Process the supported ORF types */
+
+ suck_push(sr, length, &ssr) ;
- for (i = 0 ; i < entry.num ; i++)
+ while (number--)
{
- type = stream_getc(s);
- mode = stream_getc(s);
+ qafx_bit_t qbs ;
- /* ORF Mode error check */
+ uint8_t type = suck_b(sr) ;
+ uint8_t mode = suck_b(sr) ;
+
+ /* ORF Mode error check */
switch (mode)
{
- case ORF_MODE_BOTH:
- case ORF_MODE_SEND:
- case ORF_MODE_RECEIVE:
+ case BGP_CAP_ORFT_M_RECV:
+ case BGP_CAP_ORFT_M_SEND:
+ case BGP_CAP_ORFT_M_BOTH:
break;
default:
- bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode);
- continue;
- }
- /* ORF Type and afi/safi error checks */
- /* capcode versus type */
- switch (hdr->code)
+ zlog_info ("%s Invalid send/receive 'mode' value %d"
+ " in ORF capability",
+ connection->host, mode) ;
+ return -1 ;
+ } ;
+
+ /* ORF Type and afi/safi sexing */
+ qbs = 0 ;
+ switch (cap_code)
{
- case CAPABILITY_CODE_ORF:
+ case BGP_CAN_ORF:
switch (type)
{
- case ORF_TYPE_PREFIX:
- break;
+ case BGP_CAP_ORFT_T_PFIX:
+ open_recv->can_orf_prefix |= bgp_cap_form_new ;
+ qbs = qafx_ipv4_unicast_bit
+ | qafx_ipv4_multicast_bit
+ | qafx_ipv6_unicast_bit ;
+ break ;
default:
- bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode);
- continue;
+ break ;
}
break;
- case CAPABILITY_CODE_ORF_OLD:
+ case BGP_CAN_ORF_pre:
switch (type)
{
- case ORF_TYPE_PREFIX_OLD:
- break;
+ case BGP_CAP_ORFT_T_PFIX_pre:
+ open_recv->can_orf_prefix |= bgp_cap_form_old ;
+ qbs = qafx_ipv4_unicast_bit
+ | qafx_ipv4_multicast_bit
+ | qafx_ipv6_unicast_bit ;
+ break ;
default:
- bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode);
- continue;
+ break ;
}
- break;
+ break ;
default:
- bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode);
- continue;
- }
+ break ;
+ } ;
- /* AFI vs SAFI */
- if (!((afi == AFI_IP && safi == SAFI_UNICAST)
- || (afi == AFI_IP && safi == SAFI_MULTICAST)
- || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
+ if ((qbs & qb) == 0)
{
- bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode);
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Addr-family %d/%d has"
+ " ORF type/mode %d/%d not supported",
+ connection->host, mp.afi, mp.safi, type, mode) ;
continue;
- }
+ } ;
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s OPEN has %s ORF capability"
" as %s for afi/safi: %d/%d",
- session->host, LOOKUP (orf_type_str, type),
+ connection->host, LOOKUP (orf_type_str, type),
LOOKUP (orf_mode_str, mode),
- entry.mpc.afi, safi);
+ mp.afi, mp.safi) ;
+ if (mode & BGP_CAP_ORFT_M_SEND)
+ open_recv->can_orf_prefix_send |= qb ;
+ if (mode & BGP_CAP_ORFT_M_RECV)
+ open_recv->can_orf_prefix_recv |= qb ;
- if (hdr->code == CAPABILITY_CODE_ORF)
- session->open_recv->can_orf_prefix |= bgp_cap_form_new;
- else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
- session->open_recv->can_orf_prefix |= bgp_cap_form_old;
- else
- {
- bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode);
- continue;
- }
+ confirm((BGP_CAP_ORFT_M_RECV & BGP_CAP_ORFT_M_SEND) == 0) ;
- qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
- switch (mode)
- {
- case ORF_MODE_BOTH:
- session->open_recv->can_orf_prefix_send |= qb;
- session->open_recv->can_orf_prefix_recv |= qb;
- break;
- case ORF_MODE_SEND:
- session->open_recv->can_orf_prefix_send |= qb;
- break;
- case ORF_MODE_RECEIVE:
- session->open_recv->can_orf_prefix_recv |= qb;
- break;
- }
- }
- return 0;
-}
+ confirm((BGP_CAP_ORFT_M_SEND & BGP_CAP_ORFT_M_SEND) != 0) ;
+ confirm((BGP_CAP_ORFT_M_BOTH & BGP_CAP_ORFT_M_SEND) != 0) ;
+ confirm((BGP_CAP_ORFT_M_RECV & BGP_CAP_ORFT_M_RECV) != 0) ;
+ confirm((BGP_CAP_ORFT_M_BOTH & BGP_CAP_ORFT_M_RECV) != 0) ;
+ } ;
+
+ /* Should now be exactly at the end. */
+ suck_pop_exact(sr, &ssr) ;
+
+ return 0;
+} ;
+/*------------------------------------------------------------------------------
+ * Process value of Graceful Restart -- BGP_CAN_G_RESTART -- RFC2918
+ *
+ * Capability is: time -- word
+ * AFI -- word )
+ * SAFI -- byte ) repeated 0 or more times
+ * flag -- byte )
+ *
+ * This is a variable length capability, minimum size already checked.
+ *
+ * The sr covers from the start to the end of the capability value.
+ *
+ * Returns: 0 => OK
+ * -1 => malformed !
+ */
static int
-bgp_msg_capability_orf (bgp_connection connection, struct capability_header *hdr)
+bgp_msg_capability_restart (bgp_connection connection, sucker sr)
{
- struct stream *s = connection->ibuf;
- size_t end = stream_get_getp (s) + hdr->length;
+ bgp_open_state open_recv = connection->open_recv;
+ u_int16_t restart_flag_time ;
+ int length ;
- assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
+ length = suck_left(sr) ; /* total length of value, for reporting */
- /* 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).
+ /* RFC4724: "If more than one instance of the Graceful Restart Capability
+ * is carried in the capability advertisement, the receiver of
+ * the advertisement MUST ignore all but the last instance..."
*/
- do
+
+ open_recv->can_g_restart = 1;
+
+ /* Deal with the restart time and restarted flag */
+ restart_flag_time = suck_w(sr) ;
+
+ open_recv->has_restarted = (restart_flag_time & BGP_CAP_GR_T_R_FLAG) != 0 ;
+ open_recv->restart_time = restart_flag_time & BGP_CAP_GR_T_MASK ;
+
+ open_recv->can_preserve = 0 ;
+ open_recv->has_preserved = 0 ;
+
+ if (BGP_DEBUG (normal, NORMAL))
{
- if (bgp_msg_capability_orf_entry (connection, hdr) == -1)
- return -1;
- }
- while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
+ zlog_debug ("%s OPEN has Graceful Restart capability", connection->host);
+ zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
+ connection->host, open_recv->has_restarted ? " " : " not ",
+ open_recv->restart_time);
+ } ;
- return 0;
-}
+ if ((suck_left(sr) % BGP_CAP_GRE_L) != 0)
+ {
+ zlog_info ("%s Graceful Restart Capability length error,"
+ " Cap length %u",
+ connection->host, length);
+ return -1;
+ } ;
-static void
-bgp_msg_capability_orf_not_support (char *host, afi_t afi, safi_t safi,
- u_char type, u_char mode)
+ while (suck_left(sr) > 0)
+ {
+ iAFI_SAFI_t mp ;
+ uint8_t flags ;
+ qafx_bit_t qb ;
+
+ mp.afi = suck_w(sr) ;
+ mp.safi = suck_b(sr) ;
+ flags = suck_b(sr) ;
+
+ qb = qafx_bit_from_iAFI_iSAFI(mp.afi, mp.safi) ;
+
+ if (qb == 0)
+ {
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
+ " Ignore the Graceful Restart capability",
+ connection->host, mp.afi, mp.safi);
+ }
+ else
+ {
+ /* Now can register the capability */
+
+ if (connection->session->open_send->can_mp_ext & qb)
+ {
+ qafx_bit_t has ;
+ if (flags & BGP_CAP_GRE_F_FORW)
+ has = qb ;
+ else
+ has = 0 ;
+
+ open_recv->can_preserve |= qb ;
+ open_recv->has_preserved |= has ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Address family %s is%spreserved",
+ connection->host,
+ afi_safi_print (mp.afi, mp.safi),
+ has ? " " : " not ") ;
+ }
+ else
+ {
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
+ " Ignore the Graceful Restart capability",
+ connection->host, mp.afi, mp.safi);
+ } ;
+ } ;
+ } ;
+
+ return 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Process value of AS4 capability -- BGP_CAN_AS4 -- RFC4893
+ *
+ * Capability is: ASN -- long word (4 bytes)
+ *
+ * This is a fixed length capability, so that's been dealt with.
+ *
+ * Validation of ASN and cross-check against my_as2, done elsewhere.
+ *
+ * Returns: 0 => OK
+ */
+static int
+bgp_msg_capability_as4 (bgp_connection connection, sucker sr)
{
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
- host, afi, safi, type, mode);
-}
+ bgp_open_state open_recv = connection->open_recv ;
+
+ open_recv->can_as4 = 1 ;
+ open_recv->my_as = suck_l(sr) ;
+
+ if (BGP_DEBUG (as4, AS4))
+ zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
+ connection->host, open_recv->my_as) ;
+
+ return 0 ;
+} ;
+
+/*==============================================================================
+ * BGP UPDATE message
+ */
/* Parse BGP Update packet. */
static int
@@ -1054,23 +1289,26 @@ bgp_msg_update_receive (bgp_connection connection, bgp_size_t size)
return 0;
}
-/* Keepalive treatment function -- get keepalive send keepalive */
+/*==============================================================================
+ * BGP KEEPALIVE message
+ */
static int
bgp_msg_keepalive_receive (bgp_connection connection, bgp_size_t size)
{
- bgp_session session = connection->session;
-
- assert(session);
-
if (BGP_DEBUG (keepalive, KEEPALIVE))
- zlog_debug ("%s KEEPALIVE rcvd", session->host);
+ zlog_debug ("%s KEEPALIVE rcvd", connection->host);
+
+ if (size != 0)
+ return bgp_msg_header_bad_len(connection, BGP_MT_KEEPALIVE, size) ;
bgp_fsm_event(connection, bgp_fsm_Receive_KEEPALIVE_message);
return 0;
}
-/* Notify message treatment function. */
+/*==============================================================================
+ * BGP NOTIFICATION message
+ */
static void
bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size)
{
@@ -1080,8 +1318,7 @@ bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size)
bgp_size_t expect = size - 2;
notification = bgp_notify_new(code, subcode, expect);
- notification = bgp_notify_append_data(notification,
- stream_pnt(connection->ibuf), expect);
+ bgp_notify_append_data(notification, stream_pnt(connection->ibuf), expect);
bgp_fsm_notification_exception(connection, notification);
}
@@ -1105,6 +1342,6 @@ bgp_msg_notify_send_with_data (bgp_connection connection,
{
bgp_notify notification;
notification = bgp_notify_new(code, sub_code, datalen);
- notification = bgp_notify_append_data(notification, data, datalen);
+ bgp_notify_append_data(notification, data, datalen);
bgp_fsm_raise_exception(connection, except, notification);
}
diff --git a/bgpd/bgp_msg_read.h b/bgpd/bgp_msg_read.h
index f846453f..100cd597 100644
--- a/bgpd/bgp_msg_read.h
+++ b/bgpd/bgp_msg_read.h
@@ -24,6 +24,7 @@
#define BGP_MSG_READ_H_
#include "bgpd/bgp_common.h"
+#include "bgpd/bgp_notification.h"
extern bgp_size_t
bgp_msg_get_mlen(uint8_t* p) ;
@@ -34,4 +35,7 @@ bgp_msg_check_header(bgp_connection connection);
extern void
bgp_msg_dispatch(bgp_connection connection);
+extern bgp_notify
+bgp_msg_noms_o_bad_id(bgp_notify notification, bgp_id_t id) ;
+
#endif /* BGP_MSG_READ_H_ */
diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c
index c321df59..ce4bf1b3 100644
--- a/bgpd/bgp_msg_write.c
+++ b/bgpd/bgp_msg_write.c
@@ -127,10 +127,10 @@ bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
while (length--)
{
sprintf (c, form, *p++) ;
- text_form = bgp_notify_append_data(text_form, c, strlen(c)) ;
+ bgp_notify_append_data(text_form, c, strlen(c)) ;
form = " %02x" ;
} ;
- text_form = bgp_notify_append_data(text_form, "\0", 1) ;
+ bgp_notify_append_data(text_form, "\0", 1) ;
/* TODO: restore bgp_notify_print */
#if 0
@@ -231,11 +231,9 @@ bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state)
if (BGP_DEBUG (normal, NORMAL))
{
- struct in_addr bgp_id ;
char buf[INET_ADDRSTRLEN] ;
- bgp_id.s_addr = htonl(open_state->bgp_id) ;
- inet_ntop(AF_INET, &bgp_id.s_addr, buf, INET_ADDRSTRLEN) ;
+ inet_ntop(AF_INET, &open_state->bgp_id, buf, INET_ADDRSTRLEN) ;
zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",
connection->host, BGP_VERSION_4, open_state->my_as,
@@ -610,7 +608,7 @@ bgp_msg_orf_part(struct stream* s, bgp_connection connection,
orf_type = entry->orf_type ;
orf_type_sent = entry->orf_type ;
- if ((orf_type == BGP_ORF_T_PREFIX) && connection->route_refresh_pre)
+ if ((orf_type == BGP_ORF_T_PREFIX) && connection->orf_prefix_pre)
orf_type_sent = BGP_ORF_T_PREFIX_pre ;
stream_putc(s, orf_type_sent) ; /* ORF entries type */
diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c
index 6676b346..2dc6952e 100644
--- a/bgpd/bgp_notification.c
+++ b/bgpd/bgp_notification.c
@@ -22,11 +22,13 @@
*/
#include <string.h>
+#include <netinet/in.h>
#include "lib/zassert.h"
#include "lib/memory.h"
#include "bgpd/bgp_notification.h"
+#include "bgpd/bgp_open_state.h"
/*==============================================================================
* A bgp_notify structure encapsulates the contents of a BGP NOTIFICATION
@@ -41,9 +43,9 @@
* Rounds up to multiple of 32, such that is always at least 16 bytes available.
*/
static inline bgp_size_t
-bgp_notify_size(bgp_size_t length)
+bgp_notify_size(bgp_size_t size)
{
- return sizeof(struct bgp_notify) + (((length + 32 + 16 - 1) / 32) * 32) ;
+ return (size == 0) ? 0 : ((size + 32 + 16 - 1) / 32) * 32 ;
} ;
/*==============================================================================
@@ -60,15 +62,19 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
bgp_size_t expect)
{
bgp_notify notification ;
- bgp_size_t size = bgp_notify_size(expect) ;
- notification = XCALLOC(MTYPE_BGP_NOTIFY, size) ;
+ notification = XCALLOC(MTYPE_BGP_NOTIFY, sizeof(struct bgp_notify)) ;
notification->code = code ;
notification->subcode = subcode ;
- notification->size = size ;
+ notification->size = bgp_notify_size(expect) ;
notification->length = 0 ;
+ if (notification->size != 0)
+ notification->data = XCALLOC(MTYPE_TMP, notification->size) ;
+ else
+ notification->data = NULL ;
+
return notification ;
} ;
@@ -81,7 +87,11 @@ extern void
bgp_notify_free(bgp_notify notification)
{
if (notification != NULL)
- XFREE(MTYPE_BGP_NOTIFY, notification) ;
+ {
+ if (notification->data != NULL)
+ XFREE(MTYPE_TMP, notification->data) ;
+ XFREE(MTYPE_BGP_NOTIFY, notification) ;
+ } ;
} ;
/*------------------------------------------------------------------------------
@@ -91,16 +101,25 @@ extern bgp_notify
bgp_notify_dup(bgp_notify notification)
{
bgp_notify duplicate ;
- bgp_size_t size ;
if (notification == NULL)
return NULL ;
- size = bgp_notify_size(notification->length) ;
- duplicate = XMALLOC(MTYPE_BGP_NOTIFY, size) ;
+ duplicate = XMALLOC(MTYPE_BGP_NOTIFY, sizeof(struct bgp_notify)) ;
+ *duplicate = *notification ;
- memcpy((void*)duplicate, (void*)notification, size) ;
- duplicate->size = size ;
+ if (notification->length == 0)
+ {
+ duplicate->size = 0 ;
+ duplicate->data = NULL ;
+ }
+ else
+ {
+ bgp_size_t size = bgp_notify_size(duplicate->length) ;
+ duplicate->size = size ;
+ duplicate->data = XCALLOC(MTYPE_TMP, size) ;
+ memcpy(duplicate->data, notification->data, duplicate->length) ;
+ } ;
return duplicate ;
} ;
@@ -113,8 +132,8 @@ bgp_notify_dup(bgp_notify notification)
extern void
bgp_notify_unset(bgp_notify* p_notification)
{
- if (*p_notification != NULL)
- XFREE(MTYPE_BGP_NOTIFY, *p_notification) ; /* sets *p_notification NULL */
+ bgp_notify_free(*p_notification) ; /* free anything that's there */
+ *p_notification = NULL ;
} ;
/*------------------------------------------------------------------------------
@@ -159,22 +178,44 @@ bgp_notify_set_mov(bgp_notify* p_dst, bgp_notify* p_src)
} ;
/*==============================================================================
+ * Set new Code and Subcode and discard and data accumulated so far.
+ */
+extern bgp_notify
+bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
+ bgp_nom_subcode_t subcode)
+{
+ if (notification == NULL)
+ return bgp_notify_new(code, subcode, 0) ;
+
+ notification->code = code ;
+ notification->subcode = subcode ;
+ notification->length = 0 ;
+
+ return notification ;
+} ;
+
+/*==============================================================================
* Append data to given notification
*
* Copes with zero length append.
*
* NB: returns possibly NEW ADDRESS of the notification.
*/
-extern bgp_notify
+extern void
bgp_notify_append_data(bgp_notify notification, const void* data,
bgp_size_t len)
{
bgp_size_t new_length = notification->length + len ;
- if ((sizeof(struct bgp_notify) + new_length) > notification->size)
+ if (new_length > notification->size)
{
bgp_size_t size = bgp_notify_size(new_length) ;
- notification = XREALLOC(MTYPE_BGP_NOTIFY, notification, size) ;
+
+ if (notification->size == 0)
+ notification->data = XCALLOC(MTYPE_TMP, size) ;
+ else
+ notification->data = XREALLOC(MTYPE_TMP, notification->data, size) ;
+
memset((char*)notification + notification->size, 0,
size - notification->size) ;
notification->size = size ;
@@ -184,6 +225,33 @@ bgp_notify_append_data(bgp_notify notification, const void* data,
memcpy((char*)(notification->data) + notification->length, data, len) ;
notification->length = new_length ;
+} ;
- return notification ;
+/*------------------------------------------------------------------------------
+ * Append one byte
+ */
+extern void
+bgp_notify_append_b(bgp_notify notification, uint8_t b)
+{
+ bgp_notify_append_data(notification, &b, 1) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Append one word (uint16_t), in network byte order
+ */
+extern void
+bgp_notify_append_w(bgp_notify notification, uint16_t w)
+{
+ w = htons(w) ;
+ bgp_notify_append_data(notification, &w, 2) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Append one long (uint32_t), in network byte order
+ */
+extern void
+bgp_notify_append_l(bgp_notify notification, uint32_t l)
+{
+ l = htonl(l) ;
+ bgp_notify_append_data(notification, &l, 4) ;
} ;
diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h
index 4d8d4737..f225b492 100644
--- a/bgpd/bgp_notification.h
+++ b/bgpd/bgp_notification.h
@@ -49,7 +49,7 @@ struct bgp_notify
bgp_size_t length ;
bgp_size_t size ;
- char data[] ;
+ ptr_t data ;
} ;
/*==============================================================================
@@ -158,9 +158,19 @@ bgp_notify_set_subcode(bgp_notify notification, bgp_nom_subcode_t subcode)
} ;
extern bgp_notify
+bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
+ bgp_nom_subcode_t subcode) ;
+extern void
bgp_notify_append_data(bgp_notify notification, const void* data,
bgp_size_t len) ;
+extern void
+bgp_notify_append_b(bgp_notify notification, uint8_t b) ;
+extern void
+bgp_notify_append_w(bgp_notify notification, uint16_t w) ;
+
+extern void
+bgp_notify_append_l(bgp_notify notification, uint32_t l) ;
Inline bgp_nom_code_t
bgp_notify_get_code(bgp_notify notification)
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 9139c550..038c7c72 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -41,7 +41,7 @@ struct capability_mp_data
};
#pragma pack(1)
-struct capability_orf_entry
+struct capability_orf_entry
{
struct capability_mp_data mpc;
u_char num;
@@ -90,13 +90,13 @@ struct capability_gr
/* Cooperative Route Filtering Capability. */
/* ORF Type */
-#define ORF_TYPE_PREFIX 64
+#define ORF_TYPE_PREFIX 64
#define ORF_TYPE_PREFIX_OLD 128
/* ORF Mode */
-#define ORF_MODE_RECEIVE 1
-#define ORF_MODE_SEND 2
-#define ORF_MODE_BOTH 3
+#define ORF_MODE_RECEIVE 1
+#define ORF_MODE_SEND 2
+#define ORF_MODE_BOTH 3
/* Capability Message Action. */
#define CAPABILITY_ACTION_SET 0
@@ -108,7 +108,6 @@ struct capability_gr
extern const struct message capcode_str[];
extern const int capcode_str_max;
-extern const size_t cap_minsizes[];
extern const struct message orf_type_str[];
extern const int orf_type_str_max;
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
index a8f880af..3be152cc 100644
--- a/bgpd/bgp_open_state.c
+++ b/bgpd/bgp_open_state.c
@@ -87,6 +87,21 @@ bgp_open_state_unset(bgp_open_state* p_state)
*p_state = NULL ;
} ;
+/*------------------------------------------------------------------------------
+ * Set pointer to open_state and unset source pointer
+ *
+ * Frees any existing open_state at the destination.
+ *
+ * NB: responsibility for the open_state structure passes to the destination.
+ */
+extern void
+bgp_open_state_set_mov(bgp_open_state* p_dst, bgp_open_state* p_src)
+{
+ bgp_open_state_free(*p_dst) ;
+ *p_dst = *p_src ;
+ *p_src = NULL ;
+} ;
+
/*==============================================================================
* Construct new bgp_open_state for the given peer -- allocate if required.
*
@@ -124,6 +139,9 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
/* Announce self as AS4 speaker if required */
state->can_as4 = ((peer->cap & PEER_CAP_AS4_ADV) != 0) ;
+ state->my_as2 = (state->my_as > BGP_AS2_MAX ) ? BGP_ASN_TRANS
+ : state->my_as ;
+
/* Fill in the supported AFI/SAFI */
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
@@ -169,10 +187,10 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
state->restart_time = 0 ;
} ;
- /* TODO: check not restarting and not preserving forwarding state (?) */
+ /* TODO: check not has restarted and not preserving forwarding state (?) */
state->can_preserve = 0 ; /* cannot preserve forwarding */
state->has_preserved = 0 ; /* has not preserved forwarding */
- state->restarting = 0 ; /* is not restarting */
+ state->has_restarted = 0 ; /* has not restarted */
return state;
}
@@ -231,8 +249,10 @@ bgp_peer_open_state_receive(bgp_peer peer)
bgp_session session = peer->session;
bgp_open_state open_send = session->open_send;
bgp_open_state open_recv = session->open_recv;
- int afi;
- int safi;
+ qAFI_t afi;
+ qSAFI_t safi;
+ qafx_bit_t qbs ;
+ int recv ;
/* Check neighbor as number. */
assert(open_recv->my_as == peer->as);
@@ -262,19 +282,36 @@ bgp_peer_open_state_receive(bgp_peer peer)
if (open_recv->can_as4)
SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
- /* AFI/SAFI */
- /* Ignore capability when override-capability is set. */
+ /* AFI/SAFI -- as received, or assumed or overridden */
+
+ if (!open_recv->can_capability ||
+ CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ {
+ /* There were no capabilities, or are OVERRIDING AFI/SAFI, so force
+ * not having received any AFI/SAFI, but apply this set.
+ */
+ recv = 0 ;
+ qbs = qafx_ipv4_unicast_bit | qafx_ipv4_multicast_bit |
+ qafx_ipv6_unicast_bit | qafx_ipv6_multicast_bit |
+ qafx_ipv4_mpls_vpn_bit ;
+ }
+ else
+ {
+ /* Use the AFI/SAFI received, if any. */
+ recv = 1 ;
+ qbs = open_recv->can_mp_ext ;
+ }
+
if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
{
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
{
- qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
- if (qb & open_recv->can_mp_ext)
+ qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi) ;
+ if (qb & qbs)
{
- peer->afc_recv[afi][safi] = 1;
- assert(peer->afc[afi][safi]);
- peer->afc_nego[afi][safi] = 1;
+ peer->afc_recv[afi][safi] = recv ;
+ peer->afc_nego[afi][safi] = peer->afc[afi][safi] ;
}
}
}
@@ -289,7 +326,7 @@ bgp_peer_open_state_receive(bgp_peer peer)
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
{
- qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
+ qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi);
if (qb & open_recv->can_orf_prefix_send)
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV);
if (qb & open_recv->can_orf_prefix_recv)
@@ -320,7 +357,7 @@ bgp_peer_open_state_receive(bgp_peer peer)
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
{
- qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
+ qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi);
if (peer->afc[afi][safi] && (qb & open_recv->can_g_restart))
{
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
@@ -334,14 +371,4 @@ bgp_peer_open_state_receive(bgp_peer peer)
#if 0
int restarting ; /* Restart State flag */
#endif
-
- /* Override capability. */
- if (!open_recv->can_capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- {
- peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST];
- peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST];
- peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST];
- peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
- }
-
}
diff --git a/bgpd/bgp_open_state.h b/bgpd/bgp_open_state.h
index e9529208..413fc07d 100644
--- a/bgpd/bgp_open_state.h
+++ b/bgpd/bgp_open_state.h
@@ -63,15 +63,30 @@ struct bgp_cap_unknown /* to capture unknown capability */
uint8_t value[] ;
} ;
+typedef struct bgp_cap_orf* bgp_cap_orf ;
+struct bgp_cap_orf
+{
+ flag_t known_afi_safi ;
+ flag_t known_orf_type ;
+
+ iAFI_t afi ;
+ iSAFI_t safi ;
+
+ uint8_t type ;
+ flag_t send ;
+ flag_t recv ;
+} ;
+
struct bgp_open_state
{
as_t my_as ; /* generic ASN */
unsigned holdtime ; /* in seconds */
- bgp_id_ht bgp_id ; /* an IPv4 address as *host* uint32_t */
+ bgp_id_t bgp_id ; /* an IPv4 address -- *network order* */
- int can_capability ; /* false => don't send capabilities */
+ int can_capability ; /* false => don't do capabilities */
int can_as4 ; /* true/false */
+ as2_t my_as2 ; /* AS2 from OPEN message */
qafx_set_t can_mp_ext ; /* will accept, may send these */
@@ -87,7 +102,7 @@ struct bgp_open_state
qafx_set_t can_preserve ; /* can preserve forwarding for these */
qafx_set_t has_preserved ; /* has preserved forwarding for these */
- int restarting ; /* Restart State flag */
+ int has_restarted ; /* Restart State flag */
int restart_time ; /* Restart Time in seconds */
struct vector unknowns ; /* list of bgp_cap_unknown */
@@ -107,6 +122,9 @@ extern void
bgp_open_state_unset(bgp_open_state* state) ;
extern void
+bgp_open_state_set_mov(bgp_open_state* p_dst, bgp_open_state* p_src) ;
+
+extern void
bgp_open_state_unknown_add(bgp_open_state state, uint8_t code,
void* value, bgp_size_t length) ;
extern int
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 7814e111..2456706f 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -827,7 +827,7 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
{
bgp_notify notification;
notification = bgp_notify_new(code, sub_code, datalen);
- notification = bgp_notify_append_data(notification, data, datalen);
+ bgp_notify_append_data(notification, data, datalen);
/* For debug */
bgp_notify_print (peer, notification, "sending");
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index 2de8d931..236f6d0d 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -125,13 +125,14 @@ struct bgp_session
/* The Routeing Engine sets open_send and clears open_recv before enabling
* the session, and may not change them while sEnabled/sEstablished.
*
- * The BGP Engine sets open_recv before setting the session sEstablished,
- * and will not touch it thereafter.
+ * The as_expected is the AS configured for the far end -- which is what
+ * expect to see in the incoming OPEN.
*
- * So: the Routeing Engine may use open_recv once the session is
- * sEstablished.
+ * The BGP Engine sets open_recv signalling the session eEstablished, and
+ * will not touch it thereafter.
*/
bgp_open_state open_send ; /* how to open the session */
+ as_t as_expected ; /* who to open with */
bgp_open_state open_recv ; /* set when session Established */
/* The following are set by the Routeing Engine before a session is
@@ -159,20 +160,17 @@ struct bgp_session
/* These are set by the Routeing Engine before a session is enabled,
* but are affected by the capabilities received in the OPEN message.
*
- * The Routeing Engine may read these once sEstablished (under mutex).
- *
- * In sStopped state these reflect the last state of the session.
+ * When the session is established, the BGP Engine sets these.
*/
unsigned hold_timer_interval ; /* subject to negotiation */
unsigned keepalive_timer_interval ; /* subject to negotiation */
flag_t as4 ; /* set by OPEN */
flag_t route_refresh_pre ; /* use pre-RFC version */
+ flag_t orf_prefix_pre ; /* use pre-RFC version */
/* These are cleared by the Routeing Engine before a session is enabled,
* and set by the BGP Engine when the session is established.
- *
- * In sStopped state these reflect the last state of the session.
*/
union sockunion* su_local ; /* set when session Established */
union sockunion* su_remote ; /* set when session Established */
diff --git a/lib/distribute.c b/lib/distribute.c
index 242a225c..6e7ccc67 100644
--- a/lib/distribute.c
+++ b/lib/distribute.c
@@ -34,7 +34,7 @@ struct hash *disthash;
/* Hook functions. */
void (*distribute_add_hook) (struct distribute *);
void (*distribute_delete_hook) (struct distribute *);
-
+
static struct distribute *
distribute_new (void)
{
@@ -68,11 +68,18 @@ distribute_lookup (const char *ifname)
struct distribute key;
struct distribute *dist;
+ union {
+ const char* waxon ;
+ char* waxoff ;
+ } miyagi ;
+
+ miyagi.waxon = ifname ;
+
/* temporary reference */
- key.ifname = (char *)ifname;
+ key.ifname = miyagi.waxoff ;
dist = hash_lookup (disthash, &key);
-
+
return dist;
}
@@ -107,9 +114,16 @@ distribute_get (const char *ifname)
{
struct distribute key;
+ union {
+ const char* waxon ;
+ char* waxoff ;
+ } miyagi ;
+
+ miyagi.waxon = ifname ;
+
/* temporary reference */
- key.ifname = (char *)ifname;
-
+ key.ifname = miyagi.waxoff ;
+
return hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc);
}
@@ -138,10 +152,10 @@ distribute_cmp (const struct distribute *dist1, const struct distribute *dist2)
return 1;
return 0;
}
-
+
/* Set access-list name to the distribute list. */
static struct distribute *
-distribute_list_set (const char *ifname, enum distribute_type type,
+distribute_list_set (const char *ifname, enum distribute_type type,
const char *alist_name)
{
struct distribute *dist;
@@ -163,14 +177,14 @@ distribute_list_set (const char *ifname, enum distribute_type type,
/* Apply this distribute-list to the interface. */
(*distribute_add_hook) (dist);
-
+
return dist;
}
/* Unset distribute-list. If matched distribute-list exist then
return 1. */
static int
-distribute_list_unset (const char *ifname, enum distribute_type type,
+distribute_list_unset (const char *ifname, enum distribute_type type,
const char *alist_name)
{
struct distribute *dist;
@@ -187,7 +201,7 @@ distribute_list_unset (const char *ifname, enum distribute_type type,
return 0;
free (dist->list[DISTRIBUTE_IN]);
- dist->list[DISTRIBUTE_IN] = NULL;
+ dist->list[DISTRIBUTE_IN] = NULL;
}
if (type == DISTRIBUTE_OUT)
@@ -198,7 +212,7 @@ distribute_list_unset (const char *ifname, enum distribute_type type,
return 0;
free (dist->list[DISTRIBUTE_OUT]);
- dist->list[DISTRIBUTE_OUT] = NULL;
+ dist->list[DISTRIBUTE_OUT] = NULL;
}
/* Apply this distribute-list to the interface. */
@@ -241,7 +255,7 @@ distribute_list_prefix_set (const char *ifname, enum distribute_type type,
/* Apply this distribute-list to the interface. */
(*distribute_add_hook) (dist);
-
+
return dist;
}
@@ -265,7 +279,7 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type,
return 0;
free (dist->prefix[DISTRIBUTE_IN]);
- dist->prefix[DISTRIBUTE_IN] = NULL;
+ dist->prefix[DISTRIBUTE_IN] = NULL;
}
if (type == DISTRIBUTE_OUT)
@@ -276,7 +290,7 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type,
return 0;
free (dist->prefix[DISTRIBUTE_OUT]);
- dist->prefix[DISTRIBUTE_OUT] = NULL;
+ dist->prefix[DISTRIBUTE_OUT] = NULL;
}
/* Apply this distribute-list to the interface. */
@@ -401,7 +415,7 @@ DEFUN (distribute_list,
dist = distribute_list_set (argv[2], type, argv[0]);
return CMD_SUCCESS;
-}
+}
ALIAS (distribute_list,
ipv6_distribute_list_cmd,
@@ -442,7 +456,7 @@ DEFUN (no_districute_list, no_distribute_list_cmd,
return CMD_WARNING;
}
return CMD_SUCCESS;
-}
+}
ALIAS (no_districute_list, no_ipv6_distribute_list_cmd,
"no distribute-list WORD (in|out) WORD",
@@ -472,7 +486,7 @@ DEFUN (districute_list_prefix_all,
type = DISTRIBUTE_OUT;
else
{
- vty_out (vty, "distribute list direction must be [in|out]%s",
+ vty_out (vty, "distribute list direction must be [in|out]%s",
VTY_NEWLINE);
return CMD_WARNING;
}
@@ -481,7 +495,7 @@ DEFUN (districute_list_prefix_all,
dist = distribute_list_prefix_set (NULL, type, argv[0]);
return CMD_SUCCESS;
-}
+}
ALIAS (districute_list_prefix_all,
ipv6_distribute_list_prefix_all_cmd,
@@ -512,7 +526,7 @@ DEFUN (no_districute_list_prefix_all,
type = DISTRIBUTE_OUT;
else
{
- vty_out (vty, "distribute list direction must be [in|out]%s",
+ vty_out (vty, "distribute list direction must be [in|out]%s",
VTY_NEWLINE);
return CMD_WARNING;
}
@@ -524,7 +538,7 @@ DEFUN (no_districute_list_prefix_all,
return CMD_WARNING;
}
return CMD_SUCCESS;
-}
+}
ALIAS (no_districute_list_prefix_all,
no_ipv6_distribute_list_prefix_all_cmd,
@@ -555,7 +569,7 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
type = DISTRIBUTE_OUT;
else
{
- vty_out (vty, "distribute list direction must be [in|out]%s",
+ vty_out (vty, "distribute list direction must be [in|out]%s",
VTY_NEWLINE);
return CMD_WARNING;
}
@@ -564,7 +578,7 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
dist = distribute_list_prefix_set (argv[2], type, argv[0]);
return CMD_SUCCESS;
-}
+}
ALIAS (districute_list_prefix, ipv6_distribute_list_prefix_cmd,
"distribute-list prefix WORD (in|out) WORD",
@@ -595,7 +609,7 @@ DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
type = DISTRIBUTE_OUT;
else
{
- vty_out (vty, "distribute list direction must be [in|out]%s",
+ vty_out (vty, "distribute list direction must be [in|out]%s",
VTY_NEWLINE);
return CMD_WARNING;
}
@@ -607,7 +621,7 @@ DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
return CMD_WARNING;
}
return CMD_SUCCESS;
-}
+}
ALIAS (no_districute_list_prefix, no_ipv6_distribute_list_prefix_cmd,
"no distribute-list prefix WORD (in|out) WORD",
@@ -714,7 +728,7 @@ config_write_distribute (struct vty *vty)
if (dist->list[DISTRIBUTE_IN])
{
- vty_out (vty, " distribute-list %s in %s%s",
+ vty_out (vty, " distribute-list %s in %s%s",
dist->list[DISTRIBUTE_IN],
dist->ifname ? dist->ifname : "",
VTY_NEWLINE);
@@ -723,7 +737,7 @@ config_write_distribute (struct vty *vty)
if (dist->list[DISTRIBUTE_OUT])
{
- vty_out (vty, " distribute-list %s out %s%s",
+ vty_out (vty, " distribute-list %s out %s%s",
dist->list[DISTRIBUTE_OUT],
dist->ifname ? dist->ifname : "",
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
index ddc62fd5..dfb66260 100644
--- a/lib/if_rmap.c
+++ b/lib/if_rmap.c
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -32,7 +32,7 @@ struct hash *ifrmaphash;
/* Hook functions. */
static void (*if_rmap_add_hook) (struct if_rmap *) = NULL;
static void (*if_rmap_delete_hook) (struct if_rmap *) = NULL;
-
+
static struct if_rmap *
if_rmap_new (void)
{
@@ -63,11 +63,18 @@ if_rmap_lookup (const char *ifname)
struct if_rmap key;
struct if_rmap *if_rmap;
- /* temporary copy */
- key.ifname = (char *)ifname;
+ union {
+ const char* waxon ;
+ char* waxoff ;
+ } miyagi ;
+
+ miyagi.waxon = ifname ;
+
+ /* temporary reference */
+ key.ifname = miyagi.waxoff ;
if_rmap = hash_lookup (ifrmaphash, &key);
-
+
return if_rmap;
}
@@ -100,8 +107,15 @@ if_rmap_get (const char *ifname)
{
struct if_rmap key;
- /* temporary copy */
- key.ifname = (char *)ifname;
+ union {
+ const char* waxon ;
+ char* waxoff ;
+ } miyagi ;
+
+ miyagi.waxon = ifname ;
+
+ /* temporary reference */
+ key.ifname = miyagi.waxoff ;
return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc);
}
@@ -127,9 +141,9 @@ if_rmap_hash_cmp (const void *arg1, const void* arg2)
return strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0;
}
-
+
static struct if_rmap *
-if_rmap_set (const char *ifname, enum if_rmap_type type,
+if_rmap_set (const char *ifname, enum if_rmap_type type,
const char *routemap_name)
{
struct if_rmap *if_rmap;
@@ -140,25 +154,25 @@ if_rmap_set (const char *ifname, enum if_rmap_type type,
{
if (if_rmap->routemap[IF_RMAP_IN])
XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
- if_rmap->routemap[IF_RMAP_IN]
+ if_rmap->routemap[IF_RMAP_IN]
= XSTRDUP (MTYPE_IF_RMAP_NAME, routemap_name);
}
if (type == IF_RMAP_OUT)
{
if (if_rmap->routemap[IF_RMAP_OUT])
XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
- if_rmap->routemap[IF_RMAP_OUT]
+ if_rmap->routemap[IF_RMAP_OUT]
= XSTRDUP (MTYPE_IF_RMAP_NAME, routemap_name);
}
if (if_rmap_add_hook)
(*if_rmap_add_hook) (if_rmap);
-
+
return if_rmap;
}
static int
-if_rmap_unset (const char *ifname, enum if_rmap_type type,
+if_rmap_unset (const char *ifname, enum if_rmap_type type,
const char *routemap_name)
{
struct if_rmap *if_rmap;
@@ -175,7 +189,7 @@ if_rmap_unset (const char *ifname, enum if_rmap_type type,
return 0;
XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
- if_rmap->routemap[IF_RMAP_IN] = NULL;
+ if_rmap->routemap[IF_RMAP_IN] = NULL;
}
if (type == IF_RMAP_OUT)
@@ -186,7 +200,7 @@ if_rmap_unset (const char *ifname, enum if_rmap_type type,
return 0;
XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
- if_rmap->routemap[IF_RMAP_OUT] = NULL;
+ if_rmap->routemap[IF_RMAP_OUT] = NULL;
}
if (if_rmap_delete_hook)
@@ -227,7 +241,7 @@ DEFUN (if_rmap,
if_rmap = if_rmap_set (argv[2], type, argv[0]);
return CMD_SUCCESS;
-}
+}
ALIAS (if_rmap,
if_ipv6_rmap_cmd,
@@ -268,7 +282,7 @@ DEFUN (no_if_rmap,
return CMD_WARNING;
}
return CMD_SUCCESS;
-}
+}
ALIAS (no_if_rmap,
no_if_ipv6_rmap_cmd,
@@ -279,7 +293,7 @@ ALIAS (no_if_rmap,
"Route map for input filtering\n"
"Route map for output filtering\n"
"Route map interface name\n")
-
+
/* Configuration write function. */
int
config_write_if_rmap (struct vty *vty)
@@ -297,7 +311,7 @@ config_write_if_rmap (struct vty *vty)
if (if_rmap->routemap[IF_RMAP_IN])
{
- vty_out (vty, " route-map %s in %s%s",
+ vty_out (vty, " route-map %s in %s%s",
if_rmap->routemap[IF_RMAP_IN],
if_rmap->ifname,
VTY_NEWLINE);
@@ -306,7 +320,7 @@ config_write_if_rmap (struct vty *vty)
if (if_rmap->routemap[IF_RMAP_OUT])
{
- vty_out (vty, " route-map %s out %s%s",
+ vty_out (vty, " route-map %s out %s%s",
if_rmap->routemap[IF_RMAP_OUT],
if_rmap->ifname,
VTY_NEWLINE);
diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h
index bf0f0360..40915ca5 100644
--- a/lib/qafi_safi.h
+++ b/lib/qafi_safi.h
@@ -118,6 +118,27 @@ enum qSAFI
} ;
/*==============================================================================
+ * iAFI_SAFI and qAFI_SAFI structures
+ */
+struct iAFI_SAFI
+{
+ iAFI_t afi ;
+ iSAFI_t safi ;
+} ;
+
+typedef struct iAFI_SAFI iAFI_SAFI_t ;
+typedef struct iAFI_SAFI* iAFI_SAFI ;
+
+struct qAFI_SAFI
+{
+ qAFI_t afi ;
+ qSAFI_t safi ;
+} ;
+
+typedef struct qAFI_SAFI qAFI_SAFI_t ;
+typedef struct qAFI_SAFI* qAFI_SAFI ;
+
+/*==============================================================================
* Quagga AFI/SAFI values -- original macro definitions
*/
diff --git a/lib/stream.c b/lib/stream.c
index dc636361..79ce1791 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -215,6 +215,13 @@ stream_get_endp (struct stream *s)
}
size_t
+stream_get_left (struct stream *s)
+{
+ STREAM_VERIFY_SANE(s);
+ return s->endp - s->getp ;
+}
+
+size_t
stream_get_size (struct stream *s)
{
STREAM_VERIFY_SANE(s);
diff --git a/lib/stream.h b/lib/stream.h
index 957bf495..094cf0c6 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -143,6 +143,7 @@ extern struct stream* stream_dup_pending(struct stream*) ;
extern size_t stream_resize (struct stream *, size_t);
extern size_t stream_get_getp (struct stream *);
extern size_t stream_get_endp (struct stream *);
+extern size_t stream_get_left (struct stream *s) ;
extern size_t stream_get_size (struct stream *);
extern u_char *stream_get_data (struct stream *);