summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_msg_read.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_msg_read.c')
-rw-r--r--bgpd/bgp_msg_read.c517
1 files changed, 299 insertions, 218 deletions
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index fa547789..014860cc 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -19,10 +19,172 @@
* Boston, MA 02111-1307, USA.
*/
+#include "bgp_msg_read.h"
+
+/* prototypes */
+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_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);
+static void bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size);
+static void bgp_msg_notify_send (bgp_connection connection, bgp_session_event_t except,
+ bgp_nom_code_t code, bgp_nom_subcode_t sub_code);
+static void bgp_msg_notify_send_with_data (bgp_connection connection,
+ bgp_session_event_t except, bgp_nom_code_t code, bgp_nom_subcode_t sub_code,
+ u_char *data, size_t datalen);
+
+/* read and validate header.
+ * return >= 0 number of bytes still to read
+ * 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;
+
+ assert(session);
+
+ /* Get size and type. */
+ stream_forward_getp (connection->ibuf, BGP_MARKER_SIZE);
+ memcpy (notify_data_length, stream_pnt (connection->ibuf), 2);
+ 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);
+
+ /* Marker check */
+ if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE))
+ && ! bgp_marker_all_one (connection->ibuf, BGP_MARKER_SIZE))
+ {
+ bgp_msg_notify_send (connection, bgp_session_eInvalid_msg,
+ BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_NOT_SYNC);
+ return -1;
+ }
+
+ /* 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 (BGP_DEBUG (normal, NORMAL))
+ plog_debug (session->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;
+ }
+
+ /* 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);
+ return -1;
+ }
+
+ return size - BGP_HEADER_SIZE;
+}
+
+/* Deal with the BGP message. MUST remove from ibuf before returns ! */
+void
+bgp_msg_dispatch(bgp_connection connection)
+{
+ u_char type = 0;
+ bgp_size_t size;
+ int result = 0;
+
+ /* 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 = size - BGP_HEADER_SIZE;
+
+ /* Read rest of the packet and call each sort of packet routine */
+ switch (type)
+ {
+ case BGP_MSG_OPEN:
+ bgp_msg_open_receive (connection, size);
+ break;
+ case BGP_MSG_UPDATE:
+ bgp_msg_update_receive (connection, size);
+ break;
+ case BGP_MSG_NOTIFY:
+ bgp_msg_notify_receive(connection, size);
+ break;
+ case BGP_MSG_KEEPALIVE:
+ bgp_msg_keepalive_receive(connection, size);
+ break;
+ case BGP_MSG_ROUTE_REFRESH_NEW:
+ case BGP_MSG_ROUTE_REFRESH_OLD:
+ /* TODO: refresh? */
+#if 0
+ peer->refresh_in++;
+ bgp_route_refresh_receive (peer, size);
+#endif
+ break;
+ case BGP_MSG_CAPABILITY:
+ /* TODO: dynamic capability? */
+#if 0
+ peer->dynamic_cap_in++;
+ bgp_capability_receive (peer, size);
+#endif
+ break;
+ default:
+ assert(0); /* types already validated */
+ }
+
+ /* TODO: remove message from ibuf */
+}
+
/* Receive BGP open packet and parse it into the session's
* open_recv
+ * return 0 OK
+ * return -1 error
*/
-int
+static int
bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
{
int ret;
@@ -32,7 +194,6 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
u_int16_t send_holdtime;
as_t remote_as;
as_t as4 = 0;
- struct peer *realpeer;
struct in_addr remote_id;
int capability;
u_int8_t notify_data_remote_as[2];
@@ -40,13 +201,13 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
bgp_session session = connection->session;
bgp_open_state open_recv;
+ assert(session);
+
/* To receive the parsed open message */
session->open_recv = open_recv = bgp_open_state_init_new(session->open_recv);
- realpeer = NULL;
-
/* Parse open packet. */
- version = stream_getc (peer->ibuf);
+ 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);
@@ -70,7 +231,7 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
* 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_masg_peek_for_as4_capability (peer, optlen);
+ as4 = bgp_msg_peek_for_as4_capability (connection, optlen);
}
/* Just in case we have a silly peer who sends AS4 capability set to 0 */
@@ -78,7 +239,8 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
{
zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0",
session->host);
- bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS);
return -1;
}
@@ -93,7 +255,8 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
{
zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed",
session->host);
- bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS);
return -1;
}
@@ -117,171 +280,15 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
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_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS);
return -1;
}
}
- /* Lookup peer from Open packet. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- int as = 0;
-
- realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as);
-
- if (! realpeer)
- {
- /* Peer's source IP address is check in bgp_accept(), so this
- must be AS number mismatch or remote-id configuration
- mismatch. */
- if (as)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, wrong router identifier %s",
- peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
- notify_data_remote_id, 4);
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS,
- notify_data_remote_as, 2);
- }
- return -1;
- }
- }
-
- /* When collision is detected and this peer is closed. Return
- immediately. */
- ret = bgp_collision_detect (peer, remote_id);
- if (ret < 0)
- return ret;
-
- /* Hack part. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (realpeer->status == Established
- && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE))
- {
- realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT);
- }
- else if (ret == 0 && realpeer->status != Active
- && realpeer->status != OpenSent
- && realpeer->status != OpenConfirm
- && realpeer->status != Connect)
- {
- /* XXX: This is an awful problem..
- *
- * According to the RFC we should just let this connection (of the
- * accepted 'peer') continue on to Established if the other
- * connection (the 'realpeer' one) is in state Connect, and deal
- * with the more larval FSM as/when it gets far enough to receive
- * an Open. We don't do that though, we instead close the (more
- * developed) accepted connection.
- *
- * This means there's a race, which if hit, can loop:
- *
- * FSM for A FSM for B
- * realpeer accept-peer realpeer accept-peer
- *
- * Connect Connect
- * Active
- * OpenSent OpenSent
- * <arrive here,
- * Notify, delete>
- * Idle Active
- * OpenSent OpenSent
- * <arrive here,
- * Notify, delete>
- * Idle
- * <wait> <wait>
- * Connect Connect
- *
- *
- * If both sides are Quagga, they're almost certain to wait for
- * the same amount of time of course (which doesn't preclude other
- * implementations also waiting for same time). The race is
- * exacerbated by high-latency (in bgpd and/or the network).
- *
- * The reason we do this is because our FSM is tied to our peer
- * structure, which carries our configuration information, etc.
- * I.e. we can't let the accepted-peer FSM continue on as it is,
- * cause it's not associated with any actual peer configuration -
- * it's just a dummy.
- *
- * It's possible we could hack-fix this by just bgp_stop'ing the
- * realpeer and continueing on with the 'transfer FSM' below.
- * Ideally, we need to seperate FSMs from struct peer.
- *
- * Setting one side to passive avoids the race, as a workaround.
- */
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s peer status is %s close connection",
- realpeer->host, LOOKUP (bgp_status_msg,
- realpeer->status));
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONNECT_REJECT);
-
- return -1;
- }
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)",
- peer->host,
- LOOKUP (bgp_status_msg, realpeer->status));
-
- bgp_stop (realpeer);
-
- /* Transfer file descriptor. */
- realpeer->fd = peer->fd;
- peer->fd = -1;
-
- /* Transfer input buffer. */
- stream_free (realpeer->ibuf);
- realpeer->ibuf = peer->ibuf;
- realpeer->packet_size = peer->packet_size;
- peer->ibuf = NULL;
-
- /* Transfer status. */
- realpeer->status = peer->status;
- bgp_stop (peer);
-
- /* peer pointer change. Open packet send to neighbor. */
- peer = realpeer;
- bgp_open_send (peer);
- if (peer->fd < 0)
- {
- zlog_err ("bgp_open_receive peer's fd is negative value %d",
- peer->fd);
- return -1;
- }
- BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
- }
-
- /* remote router-id check. */
- if (remote_id.s_addr == 0
- || ntohl (remote_id.s_addr) >= 0xe0000000
- || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, wrong router identifier %s",
- peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
- notify_data_remote_id, 4);
- return -1;
- }
-
/* Set remote router-id */
- peer->remote_id = remote_id;
+ open_recv->bgp_id = ntohl(remote_id);
/* Peer BGP version check. */
if (version != BGP_VERSION_4)
@@ -290,7 +297,7 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad protocol version, remote requested %d, local request %d",
session->host, version, BGP_VERSION_4);
- bgp_notify_send_with_data (peer,
+ bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_VERSION,
&maxver, 1);
@@ -298,12 +305,12 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
}
/* Check neighbor as number. */
- if (remote_as != peer->as)
+ if (remote_as != session->as)
{
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer,
+ 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);
@@ -318,7 +325,7 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
if (open_recv->holdtime < 3 && open_recv->holdtime != 0)
{
- bgp_notify_send (peer,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
return -1;
@@ -338,30 +345,37 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
session->host);
}
- /* Get sockname. */
- bgp_getsockname (peer);
-
- BGP_EVENT_ADD (peer, Receive_OPEN_message);
-
- peer->packet_size = 0;
- if (peer->ibuf)
- stream_reset (peer->ibuf);
+ bgp_fsm_event(connection, bgp_fsm_Receive_OPEN_message);
return 0;
}
+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 (BGP_DEBUG (as4, AS4))
+ zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
+ session->host, as4);
+
+ return as4;
+}
/* 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_masg_peek_for_as4_capability (bgp_connection connection, u_char length)
+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);
/* The full capability parser will better flag the error.. */
if (STREAM_READABLE(s) < length)
@@ -443,6 +457,7 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
struct stream *s = connection->ibuf;
size_t end = stream_get_getp (s) + length;
bpg_session session = connection->session;
+ assert(session);
ret = 0;
error = error_data;
@@ -460,7 +475,8 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
if (STREAM_READABLE(s) < 2)
{
zlog_info ("%s Option length error", session->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -472,13 +488,14 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
if (STREAM_READABLE (s) < opt_length)
{
zlog_info ("%s Option length error", session->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_CEASE, 0);
return -1;
}
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
- peer->host, opt_type,
+ session->host, opt_type,
opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
opt_length);
@@ -486,14 +503,17 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
switch (opt_type)
{
case BGP_OPEN_OPT_AUTH:
- ret = bgp_auth_parse (peer, opt_length);
+ 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_capability_parse (peer, opt_length, &error);
+ ret = bgp_msg_capability_parse (conection, opt_length, &error);
*capability = 1;
break;
default:
- bgp_notify_send (peer,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_PARAM);
ret = -1;
@@ -510,13 +530,12 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
/* All OPEN option is parsed. Check capability when strict compare
flag is enabled.*/
- /* TODO: where is this flag in the session? */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
+ if (session->cap_strict)
{
/* If Unsupported Capability exists. */
if (error != error_data)
{
- bgp_notify_send_with_data (peer,
+ 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);
@@ -525,9 +544,9 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
/* Check local capability does not negotiated with remote
peer. */
- if (! strict_capability_same (peer))
+ if (open_recv->can_mp_ext != open_send->can_mp_ext)
{
- bgp_notify_send (peer,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_CAPBL);
return -1;
@@ -536,24 +555,20 @@ bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capabi
/* Check there is no common capability send Unsupported Capability
error. */
- if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ if (*capability && ! session->cap_override)
{
- if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
- && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
- && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
- && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
- && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
+ if (open_recv->can_mp_ext == 0)
{
- plog_err (peer->log, "%s [Error] No common capability", peer->host);
+ plog_err (session->log, "%s [Error] No common capability", session->host);
if (error != error_data)
- bgp_notify_send_with_data (peer,
+ 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_notify_send (peer,
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_CAPBL);
return -1;
@@ -586,7 +601,8 @@ bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **err
if (stream_get_getp(s) + 2 > end)
{
zlog_info ("%s Capability length error (< header)", session->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -598,13 +614,14 @@ bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **err
if (start + caphdr.length > end)
{
zlog_info ("%s Capability length error (< length)", session->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_CEASE, 0);
return -1;
}
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s OPEN has %s capability (%u), length %u",
- peer->host,
+ session->host,
LOOKUP (capcode_str, caphdr.code),
caphdr.code, caphdr.length);
@@ -628,7 +645,8 @@ bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **err
LOOKUP (capcode_str, caphdr.code),
caphdr.length,
(unsigned) cap_minsizes[caphdr.code]);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_CEASE, 0);
return -1;
}
/* we deliberately ignore unknown codes, see below */
@@ -641,8 +659,7 @@ bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **err
case CAPABILITY_CODE_MP:
{
/* Ignore capability when override-capability is set. */
- /* TODO: where is this flag in the session? */
- if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ if (! session->cap_override)
{
/* Set negotiated value. */
ret = bgp_msg_capability_mp (connection, &caphdr);
@@ -669,22 +686,22 @@ bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **err
break;
case CAPABILITY_CODE_ORF:
case CAPABILITY_CODE_ORF_OLD:
- if (bgp_capability_orf (peer, &caphdr))
+ if (bgp_msg_capability_orf (connection, &caphdr))
return -1;
break;
case CAPABILITY_CODE_RESTART:
- if (bgp_capability_restart (peer, &caphdr))
+ if (bgp_msg_capability_restart (connection, &caphdr))
return -1;
break;
case CAPABILITY_CODE_DYNAMIC:
- SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
+ 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_capability_as4 (peer, &caphdr))
+ if (!bgp_msg_capability_as4 (connection, &caphdr))
return -1;
break;
default:
@@ -726,6 +743,8 @@ bgp_msg_capability_mp (bgp_connection connection, struct capability_header *hdr)
bgp_open_state open_send = session->open_send;
qafx_bit_t qb;
+ assert(session);
+
bgp_capability_mp_data (s, &mpc);
if (BGP_DEBUG (normal, NORMAL))
@@ -762,6 +781,8 @@ bgp_capability_orf_entry (bgp_connection connection, struct capability_header *h
bgp_session session = connection->session;
qafx_bit_t qb;
+ assert(session);
+
/* ORF Entry header */
bgp_msg_capability_mp_data (s, &entry.mpc);
entry.num = stream_getc (s);
@@ -787,7 +808,8 @@ bgp_capability_orf_entry (bgp_connection connection, struct capability_header *h
zlog_info ("%s ORF Capability entry length error,"
" Cap length %u, num %u",
session->host, hdr->length, entry.num);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_msg_notify_send (connection, bgp_session_eOpen_reject,
+ BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -853,11 +875,6 @@ bgp_capability_orf_entry (bgp_connection connection, struct capability_header *h
entry.mpc.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)
- SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV);
-
if (hdr->code == CAPABILITY_CODE_ORF)
open_recv->can_orf_prefix |= bgp_cap_form_new;
else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
@@ -888,7 +905,7 @@ bgp_capability_orf_entry (bgp_connection connection, struct capability_header *h
static int
-bgp_msg_apability_orf (bgp_connection connection, struct capability_header *hdr)
+bgp_msg_capability_orf (bgp_connection connection, struct capability_header *hdr)
{
struct stream *s = connection->ibuf;
size_t end = stream_get_getp (s) + hdr->length;
@@ -917,3 +934,67 @@ bgp_msg_capability_orf_not_support (char *host, afi_t afi, safi_t safi,
zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
host, afi, safi, type, mode);
}
+
+/* Parse BGP Update packet. */
+static int
+bgp_msg_update_receive (bgp_connection connection, bgp_size_t size)
+{
+ /* TODO: got update packet, now what? */
+ bgp_fsm_event(connection, bgp_fsm_Receive_UPDATE_message);
+ return 0;
+}
+
+/* Keepalive treatment function -- get keepalive send keepalive */
+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);
+
+ bgp_fsm_event(connection, bgp_fsm_Receive_KEEPALIVE_message);
+
+ return 0;
+}
+
+/* Notify message treatment function. */
+static void
+bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size)
+{
+ bgp_notify notification;
+ bgp_nom_code_t code = stream_getc (connection->ibuf);
+ bgp_nom_subcode_t subcode = stream_getc (connection->ibuf);
+ bgp_size_t expect = size - 2;
+
+ notification = bgp_notify_new(code, subcode, datalen);
+ notification = bgp_notify_append_data(notification,
+ stream_pnt(connection->ibuf), datalen);
+
+ bgp_fsm_notification_exception(connection, notification);
+}
+
+/* Send BGP notify packet. */
+static void
+bgp_msg_notify_send (bgp_connection connection, bgp_session_event_t except,
+ bgp_nom_code_t code, bgp_nom_subcode_t sub_code)
+{
+ bgp_notify notification;
+ notification = bgp_notify_new(code, subcode, 0);
+ bgp_fsm_raise_exception(connection, except, notification);
+}
+
+
+/* Send BGP notify packet with data portion. */
+static void
+bgp_msg_notify_send_with_data (bgp_connection connection,
+ bgp_session_event_t except, bgp_nom_code_t code, bgp_nom_subcode_t sub_code,
+ u_char *data, size_t datalen)
+{
+ bgp_notify notification;
+ notification = bgp_notify_new(code, subcode, datalen);
+ notification = bgp_notify_append_data(notification, data, datalen);
+ bgp_fsm_raise_exception(connection, except, notification);
+}